/** * Updates the whole list of all items associated with all {@link FeatureController}. * * @param model the input model of all {@link FeatureController} of {@code * featureControllerGroup}. */ @SuppressWarnings("WeakerAccess") public void updateFeatureItems(MODEL model) { for (FeatureController<MODEL> featureController : featureItems.getFeatureControllers()) { dispatchFeatureUpdate(toFeatureUpdate(featureController, model)); } }
@Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); this.recyclerView = recyclerView; }
@Override public void onDetachedFromRecyclerView(RecyclerView recyclerView) { super.onDetachedFromRecyclerView(recyclerView); this.recyclerView = null; }
@Test public void registerFeatures_should_notThrowException_when_listOfViewItemsIsEmpty() { //GIVEN StubFeatureController<String> controller = new StubFeatureController<>(emptyList(), emptyList()); List<FeatureController<String>> featureControllers = singletonList(controller); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); //WHEN featuresAdapter.validateNewViewItems(controller, emptyList()); //THEN }
@Test(expected = NullPointerException.class) public void registerFeatures_should_throwExceptionWhenBindErrorDelegateIsNotSetAndAnExceptionOccurs() throws Exception { //GIVEN final LinearLayout parent = new LinearLayout(createMock(Context.class)); StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate = createNiceMock(StubAdapterViewTypeDelegate.class); expect(stubAdapterViewTypeDelegate.getViewType()).andReturn(0).anyTimes(); stubAdapterViewTypeDelegate.bindViewHolder( anyObject(ViewHolder.class), eq("a0"), eq(singletonList("payload"))); expectLastCall().andThrow(new NullPointerException()); replay(stubAdapterViewTypeDelegate); List<ViewItem> items = new ArrayList<>(); List<FeatureController<String>> featureControllers = singletonList( new StubFeatureController<>( asList(stubAdapterViewTypeDelegate), items)); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); fixAdapterForTesting(featuresAdapter); items.add(new ViewItem<>("a0", stubAdapterViewTypeDelegate)); featuresAdapter.updateFeatureItems("a"); //WHEN featuresAdapter.onBindViewHolder(new ViewHolder(parent) {}, 0, singletonList("payload")); //THEN verify(stubAdapterViewTypeDelegate); }
@Test public void updateFeatureItems_should_updateOldItems() throws Exception { //GIVEN StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate0 = new StubAdapterViewTypeDelegate(); StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate1 = new StubAdapterViewTypeDelegate(); List<ViewItem> items = new ArrayList<>(); List<FeatureController<String>> featureControllers = asList( new StubFeatureController<>( asList(stubAdapterViewTypeDelegate0, stubAdapterViewTypeDelegate1), items)); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); fixAdapterForTesting(featuresAdapter); items.add(new ViewItem<>("a0", stubAdapterViewTypeDelegate0)); items.add(new ViewItem<>("a1", stubAdapterViewTypeDelegate1)); featuresAdapter.updateFeatureItems("a"); items.clear(); items.add(new ViewItem<>("a0", stubAdapterViewTypeDelegate0)); items.add(new ViewItem<>("a1", stubAdapterViewTypeDelegate0)); featuresAdapter.updateFeatureItems("a"); //WHEN final int viewType0 = featuresAdapter.getItemViewType(0); final int viewType1 = featuresAdapter.getItemViewType(1); //THEN assertThat(viewType0, is(stubAdapterViewTypeDelegate0.getViewType())); assertThat(viewType1, is(stubAdapterViewTypeDelegate0.getViewType())); }
@Test public void registerFeatures_should_callTheBindErrorDelegateWhenThisIsSetAndAnExceptionOccurs() throws Exception { //GIVEN final LinearLayout parent = new LinearLayout(createMock(Context.class)); StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate = createNiceMock(StubAdapterViewTypeDelegate.class); expect(stubAdapterViewTypeDelegate.getViewType()).andReturn(0).anyTimes(); stubAdapterViewTypeDelegate.bindViewHolder( anyObject(ViewHolder.class), eq("a0"), eq(singletonList("payload"))); expectLastCall().andThrow(new NullPointerException()); replay(stubAdapterViewTypeDelegate); List<ViewItem> items = new ArrayList<>(); List<FeatureController<String>> featureControllers = singletonList( new StubFeatureController<>( asList(stubAdapterViewTypeDelegate), items)); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); FeaturesAdapterErrorHandler featuresAdapterErrorHandler = createMock(FeaturesAdapterErrorHandler.class); featuresAdapterErrorHandler.onBindViewHolderError(anyObject(Throwable.class), eq(0)); featuresAdapter.setFeaturesAdapterErrorHandler(featuresAdapterErrorHandler); replay(featuresAdapterErrorHandler); fixAdapterForTesting(featuresAdapter); items.add(new ViewItem<>("a0", stubAdapterViewTypeDelegate)); featuresAdapter.updateFeatureItems("a"); //WHEN featuresAdapter.onBindViewHolder(new ViewHolder(parent) {}, 0, singletonList("payload")); //THEN verify(featuresAdapterErrorHandler, stubAdapterViewTypeDelegate); }
@Test public void getItemCount_should_returnAllItems() throws Exception { //GIVEN StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate = new StubAdapterViewTypeDelegate(); List<ViewItem> items = new ArrayList<>(); List<FeatureController<String>> featureControllers = asList(new StubFeatureController<>(asList(stubAdapterViewTypeDelegate), items)); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); fixAdapterForTesting(featuresAdapter); items.add(new ViewItem<>("a0", stubAdapterViewTypeDelegate)); items.add(new ViewItem<>("a1", stubAdapterViewTypeDelegate)); featuresAdapter.updateFeatureItems("a"); //WHEN final int itemCount = featuresAdapter.getItemCount(); //THEN assertThat(itemCount, is(2)); }
@Test @SuppressWarnings("unchecked") public void onCreateViewHolder_should_useTheRightAdapterViewTypeDelegateForAGivenPosition() throws Exception { //GIVEN final LinearLayout parent = new LinearLayout(createMock(Context.class)); StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate0 = createNiceMock(StubAdapterViewTypeDelegate.class); StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate1 = createNiceMock(StubAdapterViewTypeDelegate.class); expect(stubAdapterViewTypeDelegate0.getViewType()).andReturn(0).anyTimes(); expect(stubAdapterViewTypeDelegate1.getViewType()).andReturn(1).anyTimes(); expect(stubAdapterViewTypeDelegate1.createViewHolder(anyObject(ViewGroup.class))) .andReturn(new ViewHolder(parent) {}); replay(stubAdapterViewTypeDelegate0, stubAdapterViewTypeDelegate1); List<ViewItem> items = new ArrayList<>(); List<FeatureController<String>> featureControllers = asList( new StubFeatureController<>( asList(stubAdapterViewTypeDelegate0, stubAdapterViewTypeDelegate1), items)); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); fixAdapterForTesting(featuresAdapter); items.add(new ViewItem("a0", stubAdapterViewTypeDelegate0)); items.add(new ViewItem("a1", stubAdapterViewTypeDelegate1)); featuresAdapter.updateFeatureItems("a"); //WHEN featuresAdapter.onCreateViewHolder(parent, 1); //THEN verify(stubAdapterViewTypeDelegate0, stubAdapterViewTypeDelegate1); }
@Nullable FeatureUpdate toFeatureUpdate(FeatureController<MODEL> featureController, MODEL model) { final List<ViewItem> oldItems = featureItems.getItems(featureController); final List<ViewItem> newItems = featureController.buildItems(model); if (newItems == null) { return null; } validateNewViewItems(featureController, newItems); final DiffUtilCallbackImpl callback = new DiffUtilCallbackImpl(mapViewTypeToItemComparator, oldItems, newItems); final DiffResult diffResult = calculateDiff(callback, false); return new FeatureUpdate(featureController, newItems, diffResult); }
List<FeatureUpdate> dispatchFeatureUpdates(@NonNull List<FeatureUpdate> featureUpdates) { for (FeatureUpdate featureUpdate : featureUpdates) { dispatchFeatureUpdate(featureUpdate); } return featureUpdates; }
/** * Setup method to install a list of feature controllers into the adapter. * * @param featureControllers the list of feature controllers to install in this adapter. */ public FeaturesAdapter(List<FeatureController<MODEL>> featureControllers) { featureItems = new FeatureItems<>(featureControllers); registerAdapterViewTypeDelegates(featureItems.getFeatureControllers()); }
@Test public void registerFeatures_should_assignValidViewTypesToAdapterViewTypeDelegates() throws Exception { //GIVEN StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate = new StubAdapterViewTypeDelegate(); List<FeatureController<String>> featureControllers = asList(new StubFeatureController<>(asList(stubAdapterViewTypeDelegate))); //WHEN FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); fixAdapterForTesting(featuresAdapter); //THEN assertThat(stubAdapterViewTypeDelegate.getViewType(), not(INVALID_TYPE)); }
@Test public void registerFeatures_should_notThrowException_when_listOfViewItemsIsNull() { //GIVEN StubFeatureController<String> controller = new StubFeatureController<>(emptyList(), null); List<FeatureController<String>> featureControllers = singletonList(controller); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); //WHEN featuresAdapter.validateNewViewItems(controller, null); //THEN }
@Test public void onBindViewHolder_with_payload_should_useTheRightAdapterViewTypeDelegateForAGivenPosition() throws Exception { //GIVEN final LinearLayout parent = new LinearLayout(createMock(Context.class)); StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate0 = createNiceMock(StubAdapterViewTypeDelegate.class); StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate1 = createNiceMock(StubAdapterViewTypeDelegate.class); expect(stubAdapterViewTypeDelegate0.getViewType()).andReturn(0).anyTimes(); expect(stubAdapterViewTypeDelegate1.getViewType()).andReturn(1).anyTimes(); stubAdapterViewTypeDelegate1.bindViewHolder( anyObject(ViewHolder.class), eq("a1"), eq(singletonList("payload"))); replay(stubAdapterViewTypeDelegate0, stubAdapterViewTypeDelegate1); List<ViewItem> items = new ArrayList<>(); List<FeatureController<String>> featureControllers = singletonList( new StubFeatureController<>( asList(stubAdapterViewTypeDelegate0, stubAdapterViewTypeDelegate1), items)); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); fixAdapterForTesting(featuresAdapter); items.add(new ViewItem<>("a0", stubAdapterViewTypeDelegate0)); items.add(new ViewItem<>("a1", stubAdapterViewTypeDelegate1)); featuresAdapter.updateFeatureItems("a"); //WHEN featuresAdapter.onBindViewHolder(new ViewHolder(parent) {}, 1, singletonList("payload")); //THEN verify(stubAdapterViewTypeDelegate0, stubAdapterViewTypeDelegate1); }
@Test public void getItemViewType_should_returnCorrectViewTypeOfAdapterViewTypeDelegateForAGivenPosition() throws Exception { //GIVEN StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate0 = new StubAdapterViewTypeDelegate(); StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate1 = new StubAdapterViewTypeDelegate(); List<ViewItem> items = new ArrayList<>(); List<FeatureController<String>> featureControllers = asList( new StubFeatureController<>( asList(stubAdapterViewTypeDelegate0, stubAdapterViewTypeDelegate1), items)); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); fixAdapterForTesting(featuresAdapter); items.add(new ViewItem<>("a0", stubAdapterViewTypeDelegate0)); items.add(new ViewItem<>("a1", stubAdapterViewTypeDelegate1)); featuresAdapter.updateFeatureItems("a"); //WHEN final int viewType0 = featuresAdapter.getItemViewType(0); final int viewType1 = featuresAdapter.getItemViewType(1); //THEN assertThat(viewType0, is(stubAdapterViewTypeDelegate0.getViewType())); assertThat(viewType1, is(stubAdapterViewTypeDelegate1.getViewType())); }
@Test(expected = RuntimeException.class) public void registerFeatures_should_throwException_when_delegateIsNotRegistered() throws Exception { //GIVEN StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate = createNiceMock(StubAdapterViewTypeDelegate.class); expect(stubAdapterViewTypeDelegate.getViewType()).andReturn(RecyclerView.INVALID_TYPE).anyTimes(); replay(stubAdapterViewTypeDelegate); List<ViewItem> items = new ArrayList<>(); items.add(new ViewItem<>("a0", stubAdapterViewTypeDelegate)); StubFeatureController<String> controller = new StubFeatureController<>(asList(stubAdapterViewTypeDelegate), items); List<FeatureController<String>> featureControllers = singletonList(controller); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); //WHEN featuresAdapter.validateNewViewItems(controller, items); //THEN // a RuntimeException should be thrown. }
@Test public void onBindViewHolder_should_useTheRightAdapterViewTypeDelegateForAGivenPosition() throws Exception { //GIVEN final LinearLayout parent = new LinearLayout(createMock(Context.class)); StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate0 = createNiceMock(StubAdapterViewTypeDelegate.class); StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate1 = createNiceMock(StubAdapterViewTypeDelegate.class); expect(stubAdapterViewTypeDelegate0.getViewType()).andReturn(0).anyTimes(); expect(stubAdapterViewTypeDelegate1.getViewType()).andReturn(1).anyTimes(); stubAdapterViewTypeDelegate1.bindViewHolder(anyObject(ViewHolder.class), eq("a1")); replay(stubAdapterViewTypeDelegate0, stubAdapterViewTypeDelegate1); List<ViewItem> items = new ArrayList<>(); List<FeatureController<String>> featureControllers = singletonList( new StubFeatureController<>( asList(stubAdapterViewTypeDelegate0, stubAdapterViewTypeDelegate1), items)); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); fixAdapterForTesting(featuresAdapter); items.add(new ViewItem<>("a0", stubAdapterViewTypeDelegate0)); items.add(new ViewItem<>("a1", stubAdapterViewTypeDelegate1)); featuresAdapter.updateFeatureItems("a"); //WHEN featuresAdapter.onBindViewHolder(new ViewHolder(parent) {}, 1); //THEN verify(stubAdapterViewTypeDelegate0, stubAdapterViewTypeDelegate1); }
@Test public void registerFeatures_should_notThrowException_when_delegateIsRegistered() { //GIVEN StubAdapterViewTypeDelegate stubAdapterViewTypeDelegate = createNiceMock(StubAdapterViewTypeDelegate.class); expect(stubAdapterViewTypeDelegate.getViewType()).andReturn(0).anyTimes(); replay(stubAdapterViewTypeDelegate); List<ViewItem> items = new ArrayList<>(); items.add(new ViewItem<>("a0", stubAdapterViewTypeDelegate)); items.add(new ViewItem<>("a1", stubAdapterViewTypeDelegate)); StubFeatureController<String> controller = new StubFeatureController<>(asList(stubAdapterViewTypeDelegate), items); List<FeatureController<String>> featureControllers = singletonList(controller); FeaturesAdapter<String> featuresAdapter = new FeaturesAdapter<>(featureControllers); //WHEN featuresAdapter.validateNewViewItems(controller, items); //THEN verify(stubAdapterViewTypeDelegate); } }