// 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.android.libraries.feed.common.testing.RunnableSubject.assertThatRunnable;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;

import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.widget.LinearLayout;
import com.google.android.libraries.feed.common.functional.Suppliers;
import com.google.android.libraries.feed.common.time.testing.FakeClock;
import com.google.android.libraries.feed.piet.host.AssetProvider;
import com.google.search.now.ui.piet.BindingRefsProto.ElementBindingRef;
import com.google.search.now.ui.piet.BindingRefsProto.TemplateBindingRef;
import com.google.search.now.ui.piet.ElementsProto.BindingContext;
import com.google.search.now.ui.piet.ElementsProto.BindingValue;
import com.google.search.now.ui.piet.ElementsProto.Content;
import com.google.search.now.ui.piet.ElementsProto.Element;
import com.google.search.now.ui.piet.ElementsProto.ElementList;
import com.google.search.now.ui.piet.ElementsProto.GridRow;
import com.google.search.now.ui.piet.ElementsProto.ImageElement;
import com.google.search.now.ui.piet.ElementsProto.TemplateInvocation;
import com.google.search.now.ui.piet.ElementsProto.TextElement;
import com.google.search.now.ui.piet.ElementsProto.Visibility;
import com.google.search.now.ui.piet.ElementsProto.VisibilityState;
import com.google.search.now.ui.piet.ImagesProto.Image;
import com.google.search.now.ui.piet.PietProto.Template;
import com.google.search.now.ui.piet.StylesProto.StyleIdsStack;
import com.google.search.now.ui.piet.TextProto.ParameterizedText;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
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 ElementContainerAdapter}. */
@RunWith(RobolectricTestRunner.class)
public class ElementContainerAdapterTest {

  private static final Element DUMMY_BASE_ELEMENT = Element.getDefaultInstance();
  private static final Element DEFAULT_ELEMENT =
      Element.newBuilder().setElementList(ElementList.newBuilder().build()).build();

  private static final Element DEFAULT_BOUND_ELEMENT =
      Element.newBuilder().setGridRow(GridRow.getDefaultInstance()).build();
  private static final String DEFAULT_ELEMENT_BINDING_ID = "bound-grid-element";
  private static final ElementBindingRef DEFAULT_ELEMENT_BINDING =
      ElementBindingRef.newBuilder().setBindingId(DEFAULT_ELEMENT_BINDING_ID).build();
  private static final BindingValue DEFAULT_ELEMENT_BINDING_VALUE =
      BindingValue.newBuilder()
          .setBindingId(DEFAULT_ELEMENT_BINDING_ID)
          .setElement(DEFAULT_BOUND_ELEMENT)
          .build();

  private static final String DEFAULT_TEMPLATE_ID = "inline-text-template";
  private static final Template DEFAULT_TEMPLATE =
      Template.newBuilder()
          .setTemplateId(DEFAULT_TEMPLATE_ID)
          .setElement(
              Element.newBuilder()
                  .setTextElement(
                      TextElement.newBuilder()
                          .setParameterizedText(ParameterizedText.getDefaultInstance())))
          .build();
  private static final TemplateInvocation DEFAULT_TEMPLATE_INVOCATION =
      TemplateInvocation.newBuilder()
          .setTemplateId(DEFAULT_TEMPLATE_ID)
          .addBindingContexts(
              BindingContext.newBuilder()
                  .addBindingValues(BindingValue.newBuilder().setBindingId("T1")))
          .addBindingContexts(
              BindingContext.newBuilder()
                  .addBindingValues(BindingValue.newBuilder().setBindingId("T2")))
          .build();

  private static final String DEFAULT_BOUND_TEMPLATE_ID = "bound-image-template";
  private static final Template DEFAULT_BOUND_TEMPLATE =
      Template.newBuilder()
          .setTemplateId(DEFAULT_BOUND_TEMPLATE_ID)
          .setElement(
              Element.newBuilder()
                  .setImageElement(ImageElement.newBuilder().setImage(Image.getDefaultInstance())))
          .build();
  private static final TemplateInvocation DEFAULT_BOUND_TEMPLATE_INVOCATION =
      TemplateInvocation.newBuilder()
          .setTemplateId(DEFAULT_BOUND_TEMPLATE_ID)
          .addBindingContexts(
              BindingContext.newBuilder()
                  .addBindingValues(BindingValue.newBuilder().setBindingId("BT1")))
          .addBindingContexts(
              BindingContext.newBuilder()
                  .addBindingValues(BindingValue.newBuilder().setBindingId("BT2")))
          .addBindingContexts(
              BindingContext.newBuilder()
                  .addBindingValues(BindingValue.newBuilder().setBindingId("BT3")))
          .build();
  private static final String DEFAULT_TEMPLATE_BINDING_ID = "bind-the-bound-image-template";
  private static final TemplateBindingRef DEFAULT_TEMPLATE_BINDING =
      TemplateBindingRef.newBuilder().setBindingId(DEFAULT_TEMPLATE_BINDING_ID).build();
  private static final BindingValue TEMPLATE_BINDING_VALUE =
      BindingValue.newBuilder()
          .setBindingId(DEFAULT_TEMPLATE_BINDING_ID)
          .setTemplateInvocation(DEFAULT_BOUND_TEMPLATE_INVOCATION)
          .build();

  @Mock private FrameContext frameContext;
  @Mock private HostProviders hostProviders;
  @Mock private AssetProvider assetProvider;

  private Context context;

  private TestElementContainerAdapter adapter;

  @Before
  public void setUp() {
    initMocks(this);
    context = Robolectric.buildActivity(Activity.class).get();

    when(hostProviders.getAssetProvider()).thenReturn(assetProvider);
    AdapterParameters adapterParameters =
        new AdapterParameters(context, Suppliers.of(null), hostProviders, new FakeClock(), false);

    when(frameContext.createTemplateContext(eq(DEFAULT_TEMPLATE), any(BindingContext.class)))
        .thenReturn(frameContext);
    when(frameContext.createTemplateContext(eq(DEFAULT_BOUND_TEMPLATE), any(BindingContext.class)))
        .thenReturn(frameContext);
    when(frameContext.makeStyleFor(any(StyleIdsStack.class)))
        .thenReturn(adapterParameters.defaultStyleProvider);
    when(frameContext.filterImageSourcesByMediaQueryCondition(any(Image.class)))
        .thenAnswer(invocation -> invocation.getArguments()[0]);

    // Default no-errors behavior
    when(frameContext.getTemplateInvocationBindingValue(DEFAULT_TEMPLATE_BINDING))
        .thenReturn(TEMPLATE_BINDING_VALUE);
    when(frameContext.getTemplate(DEFAULT_TEMPLATE_ID)).thenReturn(DEFAULT_TEMPLATE);
    when(frameContext.getTemplate(DEFAULT_BOUND_TEMPLATE_ID)).thenReturn(DEFAULT_BOUND_TEMPLATE);
    when(frameContext.getElementBindingValue(DEFAULT_ELEMENT_BINDING))
        .thenReturn(DEFAULT_ELEMENT_BINDING_VALUE);

    LinearLayout view = new LinearLayout(context);

    adapter = new TestElementContainerAdapter(context, adapterParameters, view);
  }

  @Test
  public void testCreateChildAdapters_elementCreatesOneAdapter() {
    adapter.createAdapter(
        Collections.singletonList(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()),
        DUMMY_BASE_ELEMENT,
        frameContext);

    // A single adapter created from the Element.
    assertThat(adapter.childAdapters).hasSize(1);
    assertThat(adapter.childAdapters.get(0)).isInstanceOf(ElementListAdapter.class);
    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(1);
    assertThat(adapter.getBaseView().getChildAt(0))
        .isSameAs(adapter.childAdapters.get(0).getView());
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {1});
  }

  @Test
  public void testCreateChildAdapters_templateCreatesMultipleAdapters() {
    adapter.createAdapter(
        Collections.singletonList(
            Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build()),
        DUMMY_BASE_ELEMENT,
        frameContext);

    // One TemplateInstanceAdapter for each BindingContext in the TemplateInvocation.
    assertThat(DEFAULT_TEMPLATE_INVOCATION.getBindingContextsCount()).isEqualTo(2);
    assertThat(adapter.childAdapters).hasSize(2);
    assertThat(adapter.childAdapters.get(0)).isInstanceOf(TextElementAdapter.class);
    assertThat(adapter.childAdapters.get(1)).isInstanceOf(TextElementAdapter.class);
    verify(frameContext)
        .createTemplateContext(DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(0));
    verify(frameContext)
        .createTemplateContext(DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(1));

    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(2);
    assertThat(adapter.getBaseView().getChildAt(0))
        .isSameAs(adapter.childAdapters.get(0).getView());
    assertThat(adapter.getBaseView().getChildAt(1))
        .isSameAs(adapter.childAdapters.get(1).getView());
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {2});
  }

  @Test
  public void testCreateChildAdapters_templateNotFound() {
    when(frameContext.getTemplate(DEFAULT_TEMPLATE_ID)).thenReturn(null);

    adapter.createAdapter(
        Collections.singletonList(
            Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build()),
        DUMMY_BASE_ELEMENT,
        frameContext);

    // No child adapters are created.
    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(0);
    assertThat(adapter.childAdapters).isEmpty();
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {0});
  }

  @Test
  public void testCreateChildAdapters_boundElement_doesNothing() {
    adapter.createAdapter(
        Collections.singletonList(
            Content.newBuilder().setBoundElement(DEFAULT_ELEMENT_BINDING).build()),
        DUMMY_BASE_ELEMENT,
        frameContext);

    // No child adapters are created.
    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(0);
    assertThat(adapter.childAdapters).isEmpty();
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {0});
  }

  @Test
  public void testCreateChildAdapters_boundElementNotFound_doesNothing() {
    when(frameContext.getElementBindingValue(DEFAULT_ELEMENT_BINDING))
        .thenReturn(BindingValue.getDefaultInstance());

    adapter.createAdapter(
        Collections.singletonList(
            Content.newBuilder().setBoundElement(DEFAULT_ELEMENT_BINDING).build()),
        DUMMY_BASE_ELEMENT,
        frameContext);

    // No child adapters are created.
    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(0);
    assertThat(adapter.childAdapters).isEmpty();
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {0});
  }

  @Test
  public void testCreateChildAdapters_boundTemplate_doesNothing() {
    adapter.createAdapter(
        Collections.singletonList(
            Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build()),
        DUMMY_BASE_ELEMENT,
        frameContext);

    // No child adapters are created.
    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(0);
    assertThat(adapter.childAdapters).isEmpty();
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {0});
  }

  @Test
  public void testCreateChildAdapters_boundTemplateNotFound_doesNothing() {
    when(frameContext.getTemplateInvocationBindingValue(DEFAULT_TEMPLATE_BINDING))
        .thenReturn(BindingValue.getDefaultInstance());

    adapter.createAdapter(
        Collections.singletonList(
            Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build()),
        DUMMY_BASE_ELEMENT,
        frameContext);

    // No child adapters are created.
    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(0);
    assertThat(adapter.childAdapters).isEmpty();
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {0});
  }

  @Test
  public void testCreateChildAdapters_boundTemplateBetweenInlineContents() {
    List<Content> contents = new ArrayList<>();
    contents.add(Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build());
    contents.add(Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build());
    contents.add(Content.newBuilder().setElement(DEFAULT_ELEMENT).build());

    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);

    // Adapters created:  2 templates, (nothing for the binding), 1 element list
    assertThat(adapter.childAdapters).hasSize(3);
    assertThat(adapter.childAdapters.get(0)).isInstanceOf(TextElementAdapter.class);
    assertThat(adapter.childAdapters.get(1)).isInstanceOf(TextElementAdapter.class);

    assertThat(adapter.childAdapters.get(2)).isInstanceOf(ElementListAdapter.class);

    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(3);
    for (int i = 0; i < 3; i++) {
      assertThat(adapter.getBaseView().getChildAt(i))
          .isSameAs(adapter.childAdapters.get(i).getView());
    }

    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {2, 0, 1});
  }

  @Test
  public void testCreateChildAdapters_failsIfAdapterNotReleased() {
    adapter.createAdapter(
        Collections.singletonList(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()),
        DUMMY_BASE_ELEMENT,
        frameContext);

    assertThatRunnable(
            () ->
                adapter.createAdapter(
                    Collections.singletonList(
                        Content.newBuilder().setElement(DEFAULT_ELEMENT).build()),
                    DUMMY_BASE_ELEMENT,
                    frameContext))
        .throwsAnExceptionOfType(IllegalStateException.class)
        .that()
        .hasMessageThat()
        .contains("release adapter before creating");
  }

  @Test
  public void testBindChildAdapters_createsAdapterIfNotAlreadyCreated() {
    adapter.bindModel(
        Collections.singletonList(Content.newBuilder().setElement(DEFAULT_ELEMENT).build()),
        DUMMY_BASE_ELEMENT,
        frameContext);

    assertThat(adapter.childAdapters).hasSize(1);
    assertThat(adapter.childAdapters.get(0)).isInstanceOf(ElementListAdapter.class);
    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(1);
  }

  @Test
  public void testBindChildAdapters_element() {
    List<Content> contents =
        Collections.singletonList(Content.newBuilder().setElement(DEFAULT_ELEMENT).build());
    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);
    ElementAdapter<? extends View, ?> mockChildAdapter = mock(ElementListAdapter.class);
    adapter.childAdapters.set(0, mockChildAdapter);

    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    verify(mockChildAdapter).bindModel(DEFAULT_ELEMENT, frameContext);
  }

  @Test
  public void testBindChildAdapters_template() {
    List<Content> contents =
        Collections.singletonList(
            Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build());
    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);
    RecyclerKey key1 = adapter.childAdapters.get(0).getKey();
    RecyclerKey key2 = adapter.childAdapters.get(1).getKey();
    TextElementAdapter mockChildAdapter1 = mock(TextElementAdapter.class);
    TextElementAdapter mockChildAdapter2 = mock(TextElementAdapter.class);
    when(mockChildAdapter1.getKey()).thenReturn(key1);
    when(mockChildAdapter2.getKey()).thenReturn(key2);
    adapter.childAdapters.set(0, mockChildAdapter1);
    adapter.childAdapters.set(1, mockChildAdapter2);

    FrameContext templateContext1 = mock(FrameContext.class);
    FrameContext templateContext2 = mock(FrameContext.class);
    when(frameContext.createTemplateContext(
            DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(0)))
        .thenReturn(templateContext1);
    when(frameContext.createTemplateContext(
            DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(1)))
        .thenReturn(templateContext2);

    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    verify(mockChildAdapter1).bindModel(DEFAULT_TEMPLATE.getElement(), templateContext1);
    verify(mockChildAdapter2).bindModel(DEFAULT_TEMPLATE.getElement(), templateContext2);
  }

  @Test
  public void testBindChildAdapters_templateNotFound() {
    when(frameContext.getTemplate(DEFAULT_TEMPLATE_ID)).thenReturn(null);

    List<Content> contents =
        Collections.singletonList(
            Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build());
    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);

    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    // No child adapters are created; binding does nothing.
    assertThat(adapter.childAdapters).isEmpty();
    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(0);
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {0});
  }

  @Test
  public void testBindChildAdapters_boundElement() {
    List<Content> contents =
        Collections.singletonList(
            Content.newBuilder().setBoundElement(DEFAULT_ELEMENT_BINDING).build());
    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);

    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(1);
    assertThat(adapter.getBaseView().getChildAt(0))
        .isSameAs(adapter.childAdapters.get(0).getView());

    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {1});
  }

  @Test
  public void testBindChildAdapters_boundTemplate() {
    List<Content> contents =
        Collections.singletonList(
            Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build());
    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);

    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(3);
    assertThat(adapter.getBaseView().getChildAt(0))
        .isSameAs(adapter.childAdapters.get(0).getView());
    assertThat(adapter.getBaseView().getChildAt(1))
        .isSameAs(adapter.childAdapters.get(1).getView());
    assertThat(adapter.getBaseView().getChildAt(2))
        .isSameAs(adapter.childAdapters.get(2).getView());

    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {3});
  }

  @Test
  public void testBindChildAdapters_boundTemplateNotFound_doesNothing() {
    when(frameContext.getTemplate(DEFAULT_BOUND_TEMPLATE_ID)).thenReturn(null);

    List<Content> contents =
        Collections.singletonList(
            Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build());
    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);

    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(0);
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {0});
  }

  @Test
  public void testBindChildAdapters_boundTemplateBindingNotFound_doesNothing() {
    when(frameContext.getTemplateInvocationBindingValue(DEFAULT_TEMPLATE_BINDING))
        .thenReturn(BindingValue.getDefaultInstance());

    List<Content> contents =
        Collections.singletonList(
            Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build());
    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);

    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(0);
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {0});
  }

  @Test
  public void testBindChildAdapters_boundTemplateBetweenInlineContents() {
    List<Content> contents = new ArrayList<>();
    contents.add(Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build());
    contents.add(Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build());
    contents.add(Content.newBuilder().setElement(DEFAULT_ELEMENT).build());

    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);
    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    // 2 templates, 3 templates, 1 element list
    assertThat(adapter.childAdapters).hasSize(6);

    assertThat(adapter.childAdapters.get(0)).isInstanceOf(TextElementAdapter.class);
    assertThat(adapter.childAdapters.get(1)).isInstanceOf(TextElementAdapter.class);

    assertThat(adapter.childAdapters.get(2)).isInstanceOf(ImageElementAdapter.class);
    assertThat(adapter.childAdapters.get(3)).isInstanceOf(ImageElementAdapter.class);
    assertThat(adapter.childAdapters.get(4)).isInstanceOf(ImageElementAdapter.class);

    assertThat(adapter.childAdapters.get(5)).isInstanceOf(ElementListAdapter.class);

    // Each of these occur 2 times; once for create and once for bind.
    verify(frameContext, times(2))
        .createTemplateContext(DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(0));
    verify(frameContext, times(2))
        .createTemplateContext(DEFAULT_TEMPLATE, DEFAULT_TEMPLATE_INVOCATION.getBindingContexts(1));

    // These only occur once because we do create and bind at the same time.
    verify(frameContext)
        .createTemplateContext(
            DEFAULT_BOUND_TEMPLATE, DEFAULT_BOUND_TEMPLATE_INVOCATION.getBindingContexts(0));
    verify(frameContext)
        .createTemplateContext(
            DEFAULT_BOUND_TEMPLATE, DEFAULT_BOUND_TEMPLATE_INVOCATION.getBindingContexts(1));
    verify(frameContext)
        .createTemplateContext(
            DEFAULT_BOUND_TEMPLATE, DEFAULT_BOUND_TEMPLATE_INVOCATION.getBindingContexts(2));

    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(6);
    for (int i = 0; i < 6; i++) {
      assertThat(adapter.getBaseView().getChildAt(i))
          .isSameAs(adapter.childAdapters.get(i).getView());
    }

    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {2, 3, 1});
  }

  @Test
  public void testUnbindChildAdapters_inline() {
    List<Content> contents = new ArrayList<>();
    contents.add(Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build());
    contents.add(Content.newBuilder().setElement(DEFAULT_ELEMENT).build());

    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);
    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    adapter.unbindModel();

    // 2 templates, 1 element list
    assertThat(adapter.childAdapters).hasSize(3);
    assertThat(adapter.childAdapters.get(0)).isInstanceOf(TextElementAdapter.class);
    assertThat(adapter.childAdapters.get(1)).isInstanceOf(TextElementAdapter.class);
    assertThat(adapter.childAdapters.get(2)).isInstanceOf(ElementListAdapter.class);

    assertThat(adapter.childAdapters.get(0).getRawModel()).isNull();
    assertThat(adapter.childAdapters.get(1).getRawModel()).isNull();
    assertThat(adapter.childAdapters.get(2).getRawModel()).isNull();

    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(3);
    for (int i = 0; i < 3; i++) {
      assertThat(adapter.getBaseView().getChildAt(i))
          .isSameAs(adapter.childAdapters.get(i).getView());
    }

    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {2, 1});
  }

  @Test
  public void testUnbindChildAdapters_boundElement() {
    List<Content> contents =
        Collections.singletonList(
            Content.newBuilder().setBoundElement(DEFAULT_ELEMENT_BINDING).build());
    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);
    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    adapter.unbindModel();

    // All (bound) adapters and views have been destroyed
    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(0);
    assertThat(adapter.childAdapters).isEmpty();
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {0});
  }

  @Test
  public void testUnbindChildAdapters_boundTemplate() {
    List<Content> contents =
        Collections.singletonList(
            Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build());
    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);
    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    adapter.unbindModel();

    // All (bound) adapters and views have been destroyed
    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(0);
    assertThat(adapter.childAdapters).isEmpty();
    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {0});
  }

  @Test
  public void testUnbindChildAdapters_boundContentBetweenInlineContents() {
    List<Content> contents = new ArrayList<>();
    contents.add(Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build());
    contents.add(Content.newBuilder().setTemplateBinding(DEFAULT_TEMPLATE_BINDING).build());
    contents.add(Content.newBuilder().setElement(DEFAULT_ELEMENT).build());

    adapter.createAdapter(contents, DUMMY_BASE_ELEMENT, frameContext);
    adapter.bindModel(contents, DUMMY_BASE_ELEMENT, frameContext);

    assertThat(adapter.childAdapters).hasSize(6);
    ImageElementAdapter mockTemplateAdapter = mock(ImageElementAdapter.class);
    adapter.childAdapters.set(3, mockTemplateAdapter);

    adapter.unbindModel();

    // The inline adapters have been unbound; the bound adapters have been destroyed.
    assertThat(adapter.childAdapters).hasSize(3);
    assertThat(adapter.childAdapters.get(0).getRawModel()).isNull();
    assertThat(adapter.childAdapters.get(1).getRawModel()).isNull();
    assertThat(adapter.childAdapters.get(2).getRawModel()).isNull();

    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(3);
    for (int i = 0; i < 3; i++) {
      assertThat(adapter.getBaseView().getChildAt(i))
          .isSameAs(adapter.childAdapters.get(i).getView());
    }

    assertThat(adapter.adaptersPerContent).isEqualTo(new int[] {2, 0, 1});

    verify(mockTemplateAdapter).unbindModel();
    verify(mockTemplateAdapter).releaseAdapter();
  }

  @Test
  public void testUnbind_visibilityWasGone() {
    List<Content> contents = new ArrayList<>();
    contents.add(Content.newBuilder().setTemplateInvocation(DEFAULT_TEMPLATE_INVOCATION).build());
    contents.add(Content.newBuilder().setElement(DEFAULT_ELEMENT).build());

    Element goneElement =
        Element.newBuilder()
            .setVisibilityState(VisibilityState.newBuilder().setDefaultVisibility(Visibility.GONE))
            .build();

    adapter.createAdapter(contents, goneElement, frameContext);
    adapter.bindModel(contents, goneElement, frameContext);

    // Nothing was created because the visibility was GONE
    assertThat(adapter.childAdapters).isEmpty();
    assertThat(adapter.adaptersPerContent).isEmpty();

    adapter.unbindModel();

    // Nothing crashes, and the adapter is still uncreated.
    assertThat(adapter.childAdapters).isEmpty();
    assertThat(adapter.adaptersPerContent).isEmpty();
    assertThat(adapter.getBaseView().getChildCount()).isEqualTo(0);
  }

  private static class TestElementContainerAdapter
      extends ElementContainerAdapter<LinearLayout, List<Content>> {

    TestElementContainerAdapter(
        Context context, AdapterParameters adapterParameters, LinearLayout view) {
      super(context, adapterParameters, view);
    }

    @Override
    List<Content> getContentsFromModel(List<Content> model) {
      return model;
    }

    @Override
    List<Content> getModelFromElement(Element baseElement) {
      throw new UnsupportedOperationException("Not used in this test");
    }

    @Override
    StyleIdsStack getSubElementStyleIdsStack() {
      return StyleIdsStack.getDefaultInstance();
    }
  }
}
