| // Copyright 2018 The Feed Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.android.libraries.feed.piet; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.MockitoAnnotations.initMocks; |
| |
| import android.app.Activity; |
| import android.content.Context; |
| import android.graphics.Typeface; |
| import android.graphics.drawable.Drawable; |
| import android.view.ViewGroup; |
| import android.widget.FrameLayout; |
| import android.widget.LinearLayout; |
| import com.google.android.libraries.feed.common.functional.Consumer; |
| import com.google.android.libraries.feed.common.functional.Supplier; |
| import com.google.android.libraries.feed.common.functional.Suppliers; |
| import com.google.android.libraries.feed.common.time.Clock; |
| import com.google.android.libraries.feed.common.time.SystemClockImpl; |
| import com.google.android.libraries.feed.common.time.testing.FakeClock; |
| import com.google.android.libraries.feed.common.ui.LayoutUtils; |
| import com.google.android.libraries.feed.host.config.DebugBehavior; |
| import com.google.android.libraries.feed.piet.PietStylesHelper.PietStylesHelperFactory; |
| import com.google.android.libraries.feed.piet.host.ActionHandler; |
| import com.google.android.libraries.feed.piet.host.AssetProvider; |
| import com.google.android.libraries.feed.piet.host.CustomElementProvider; |
| import com.google.android.libraries.feed.piet.host.EventLogger; |
| import com.google.android.libraries.feed.piet.host.HostBindingProvider; |
| import com.google.android.libraries.feed.piet.host.ImageLoader; |
| import com.google.android.libraries.feed.piet.host.StringFormatter; |
| import com.google.android.libraries.feed.piet.host.ThrowingCustomElementProvider; |
| import com.google.android.libraries.feed.piet.host.TypefaceProvider; |
| import com.google.android.libraries.feed.piet.ui.RoundedCornerMaskCache; |
| import com.google.search.now.ui.piet.ImagesProto.Image; |
| import com.google.search.now.ui.piet.PietProto.Frame; |
| import java.util.Collections; |
| import java.util.Locale; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.Mock; |
| import org.robolectric.Robolectric; |
| import org.robolectric.RobolectricTestRunner; |
| |
| /** Tests of the {@link PietManagerImpl}. */ |
| @RunWith(RobolectricTestRunner.class) |
| public class PietManagerImplTest { |
| @Mock private ActionHandler actionHandler; |
| @Mock private EventLogger eventLogger; |
| @Mock private CustomElementProvider customElementProvider; |
| |
| @Mock ImageLoader imageLoader; |
| @Mock StringFormatter stringFormatter; |
| @Mock TypefaceProvider typefaceProvider; |
| @Mock private PietStylesHelperFactory stylesHelpers; |
| |
| private Context context; |
| private ViewGroup viewGroup1; |
| private ViewGroup viewGroup2; |
| |
| private PietManagerImpl pietManager; |
| |
| @Before |
| public void setUp() throws Exception { |
| initMocks(this); |
| context = Robolectric.buildActivity(Activity.class).get(); |
| viewGroup1 = new LinearLayout(context); |
| viewGroup2 = new FrameLayout(context); |
| pietManager = |
| (PietManagerImpl) |
| PietManager.builder() |
| .setDebugBehavior(DebugBehavior.VERBOSE) |
| .setCustomElementProvider(customElementProvider) |
| .build(); |
| } |
| |
| @Test |
| public void testCreatePietFrameAdapter() { |
| Supplier<ViewGroup> cardViewSupplier = Suppliers.of(viewGroup1); |
| FrameAdapterImpl frameAdapter = |
| (FrameAdapterImpl) |
| pietManager.createPietFrameAdapter( |
| cardViewSupplier, actionHandler, eventLogger, context); |
| assertThat(frameAdapter.getParameters().parentViewSupplier).isSameInstanceAs(cardViewSupplier); |
| } |
| |
| @Test |
| public void testGetAdapterParameters() { |
| Supplier<ViewGroup> viewGroupProducer1 = Suppliers.of(viewGroup1); |
| Supplier<ViewGroup> viewGroupProducer2 = Suppliers.of(viewGroup2); |
| Context context1 = Robolectric.buildActivity(Activity.class).get(); |
| Context context2 = Robolectric.buildActivity(Activity.class).get(); |
| |
| AdapterParameters returnParams; |
| |
| // Get params for a context that does not exist |
| returnParams = pietManager.getAdapterParameters(context1, viewGroupProducer1); |
| assertThat(returnParams.parentViewSupplier).isEqualTo(viewGroupProducer1); |
| assertThat(returnParams.context).isEqualTo(context1); |
| |
| // Get params for the same context again (use cached value) |
| returnParams = pietManager.getAdapterParameters(context1, Suppliers.of(null)); |
| assertThat(returnParams.parentViewSupplier).isEqualTo(viewGroupProducer1); |
| |
| // Get params for a different context |
| returnParams = pietManager.getAdapterParameters(context2, viewGroupProducer2); |
| assertThat(returnParams.parentViewSupplier).isEqualTo(viewGroupProducer2); |
| } |
| |
| @Test |
| public void testBuilder_defaults() { |
| PietManagerImpl manager = (PietManagerImpl) PietManager.builder().build(); |
| AdapterParameters parameters = manager.getAdapterParameters(context, Suppliers.of(viewGroup1)); |
| assertThat(parameters.hostProviders.getCustomElementProvider()) |
| .isInstanceOf(ThrowingCustomElementProvider.class); |
| assertThat(parameters.clock).isInstanceOf(SystemClockImpl.class); |
| // There's no good way to test the HostBindingProvider. |
| |
| FrameAdapterImpl frameAdapter = |
| (FrameAdapterImpl) |
| manager.createPietFrameAdapter( |
| Suppliers.of(viewGroup1), actionHandler, eventLogger, context); |
| FrameContext frameContext = |
| frameAdapter.createFrameContext( |
| Frame.getDefaultInstance(), 0, Collections.emptyList(), viewGroup2); |
| assertThat(frameContext.getDebugBehavior()).isEqualTo(DebugBehavior.SILENT); |
| |
| AssetProvider assetProvider = manager.assetProvider; |
| |
| assertThat(assetProvider.isDarkTheme()).isFalse(); |
| assertThat(assetProvider.getDefaultCornerRadius()).isEqualTo(0); |
| assertThat(assetProvider.getFadeImageThresholdMs()).isEqualTo(Integer.MAX_VALUE); |
| assertThat(assetProvider.isRtL()).isFalse(); |
| } |
| |
| @Test |
| public void testBuilder_rtl() { |
| Locale defaultLocale = Locale.getDefault(); |
| |
| Locale.setDefault(Locale.forLanguageTag("ar")); |
| assertThat(LayoutUtils.isDefaultLocaleRtl()).isTrue(); |
| |
| PietManagerImpl manager = (PietManagerImpl) PietManager.builder().build(); |
| |
| assertThat(manager.assetProvider.isRtL()).isTrue(); |
| |
| // Reset the Locale so it doesn't mess up other tests |
| // (Removing this causes failures in Kokoro/Bazel testing) |
| Locale.setDefault(defaultLocale); |
| } |
| |
| @Test |
| public void testBuilder_setters() { |
| boolean isRtL = true; |
| boolean isDarkTheme = true; |
| HostBindingProvider hostBindingProvider = new HostBindingProvider(); |
| Clock clock = new FakeClock(); |
| PietManagerImpl manager = |
| (PietManagerImpl) |
| PietManager.builder() |
| .setImageLoader(imageLoader) |
| .setStringFormatter(stringFormatter) |
| .setDefaultCornerRadius(Suppliers.of(123)) |
| .setIsDarkTheme(Suppliers.of(isDarkTheme)) |
| .setIsRtL(Suppliers.of(isRtL)) |
| .setFadeImageThresholdMs(Suppliers.of(456)) |
| .setTypefaceProvider(typefaceProvider) |
| .setDebugBehavior(DebugBehavior.VERBOSE) |
| .setCustomElementProvider(customElementProvider) |
| .setHostBindingProvider(hostBindingProvider) |
| .setClock(clock) |
| .build(); |
| AdapterParameters parameters = manager.getAdapterParameters(context, Suppliers.of(viewGroup1)); |
| assertThat(parameters.hostProviders.getCustomElementProvider()) |
| .isSameInstanceAs(customElementProvider); |
| assertThat(parameters.hostProviders.getHostBindingProvider()) |
| .isSameInstanceAs(hostBindingProvider); |
| assertThat(parameters.clock).isSameInstanceAs(clock); |
| |
| FrameAdapterImpl frameAdapter = |
| (FrameAdapterImpl) |
| manager.createPietFrameAdapter( |
| Suppliers.of(viewGroup1), actionHandler, eventLogger, context); |
| FrameContext frameContext = |
| frameAdapter.createFrameContext( |
| Frame.getDefaultInstance(), 0, Collections.emptyList(), viewGroup2); |
| assertThat(frameContext.getDebugBehavior()).isEqualTo(DebugBehavior.VERBOSE); |
| |
| AssetProvider assetProvider = manager.assetProvider; |
| |
| Consumer<Drawable> drawableConsumer = drawable -> {}; |
| assetProvider.getImage(Image.getDefaultInstance(), 12, 34, drawableConsumer); |
| verify(imageLoader).getImage(Image.getDefaultInstance(), 12, 34, drawableConsumer); |
| |
| assetProvider.getRelativeElapsedString(789); |
| verify(stringFormatter).getRelativeElapsedString(789); |
| |
| Consumer<Typeface> typefaceConsumer = typeface -> {}; |
| assetProvider.getTypeface("blah", false, typefaceConsumer); |
| verify(typefaceProvider).getTypeface("blah", false, typefaceConsumer); |
| |
| assertThat(assetProvider.isDarkTheme()).isEqualTo(isDarkTheme); |
| assertThat(assetProvider.isRtL()).isEqualTo(isRtL); |
| |
| assertThat(assetProvider.getDefaultCornerRadius()).isEqualTo(123); |
| assertThat(assetProvider.getFadeImageThresholdMs()).isEqualTo(456); |
| } |
| |
| @Test |
| public void testPurgeRecyclerPools() { |
| // Test with null adapterParameters |
| pietManager.purgeRecyclerPools(); |
| |
| ElementAdapterFactory mockFactory = mock(ElementAdapterFactory.class); |
| TemplateBinder mockTemplateBinder = mock(TemplateBinder.class); |
| HostProviders hostProviders = mock(HostProviders.class); |
| RoundedCornerMaskCache maskCache = mock(RoundedCornerMaskCache.class); |
| pietManager.adapterParameters = |
| new AdapterParameters( |
| context, |
| Suppliers.of(viewGroup1), |
| hostProviders, |
| null, |
| mockFactory, |
| mockTemplateBinder, |
| new FakeClock(), |
| stylesHelpers, |
| maskCache, |
| false, |
| false); |
| pietManager.purgeRecyclerPools(); |
| verify(mockFactory).purgeRecyclerPools(); |
| verify(stylesHelpers).purge(); |
| verify(maskCache).purge(); |
| } |
| } |