content: package com.adevinta.android.barista.sample.assertion;
  
  import androidx.test.rule.ActivityTestRule;
  import com.adevinta.android.barista.internal.failurehandler.BaristaException;
  import com.adevinta.android.barista.sample.R;
  import com.adevinta.android.barista.sample.SomeViewsWithDifferentVisibilitiesActivity;
  import com.adevinta.android.barista.sample.util.SpyFailureHandlerRule;
  import org.junit.Rule;
  import org.junit.Test;
  
  import static androidx.test.espresso.matcher.ViewMatchers.withTagValue;
  import static com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assertDisplayed;
  import static com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assertNotDisplayed;
  import static com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assertNotExist;
  import static org.assertj.core.api.Assertions.assertThat;
  import static org.assertj.core.api.ThrowableAssert.catchThrowable;
  import static org.hamcrest.Matchers.is;
  
  public class VisibilityAssertionsTest {
  
    @Rule
    public ActivityTestRule<SomeViewsWithDifferentVisibilitiesActivity> activityRule =
        new ActivityTestRule<>(SomeViewsWithDifferentVisibilitiesActivity.class);
  
    @Rule
    public SpyFailureHandlerRule spyFailureHandlerRule = new SpyFailureHandlerRule();
  
    public void checkDisplayedViews() {
      assertDisplayed(R.id.visible_view);
      assertDisplayed(R.string.hello_world);
      assertDisplayed("Hello world!");
  
      spyFailureHandlerRule.assertNoEspressoFailures();
    }
  
    @Test
    public void checkDisplayed_withRepeatedViews() {
      assertDisplayed("Repeated");
      assertDisplayed(R.string.repeated);
  
      spyFailureHandlerRule.assertNoEspressoFailures();
    }
  
    @Test
    public void checkNotDisplayed_withGoneView() {
      assertNotDisplayed(R.id.repeated_view_1_gone);
  
      spyFailureHandlerRule.assertNoEspressoFailures();
    }
  
    @Test
    public void checkDisplayedViews_failsWhenInvisible() {
      Throwable thrown1 = catchThrowable(() -> assertDisplayed(R.id.invisible_view));
      assertThat(thrown1).isInstanceOf(BaristaException.class)
          .hasMessage("View (view.getId() is <" + R.id.invisible_view + "/com.adevinta.android.barista.sample:id/invisible_view>) " +
              "didn't match condition ((view has effective visibility <VISIBLE> and view.getGlobalVisibleRect()" +
              " to return non-empty rectangle))");
  
      Throwable thrown2 = catchThrowable(() -> assertDisplayed(R.string.im_invisible)); // test fails
      assertThat(thrown2).isInstanceOf(BaristaException.class)
          .hasMessage("View (an instance of android.widget.TextView and view.getText() equals string from"
              +
              " resource id: <"
              + R.string.im_invisible
              + "> [im_invisible] value: I'm invisible!) didn't match condition ((view has effective visibility <VISIBLE> and view.getGlobalVisibleRect() to return non-empty rectangle))");
  
      Throwable thrown3 = catchThrowable(() -> assertDisplayed("I'm invisible!"));
      assertThat(thrown3).isInstanceOf(BaristaException.class)
          .hasMessage("View ((an instance of android.widget.TextView and view.getText() with or" +
              " without transformation to match: is \"I'm invisible!\" or (view.getParent()" +
              " is assignable from class <class com.google.android.material.textfield.TextInputLayout>" +
              " and (view is an instance of android.view.ViewGroup and has descendant matching an instance" +
              " of android.widget.TextView and view.getText() with or without transformation to match: is \"I'm invisible!\")))) " +
              "didn't match condition ((view has effective visibility <VISIBLE> and view.getGlobalVisibleRect()" +
              " to return non-empty rectangle))");
  
      spyFailureHandlerRule.assertEspressoFailures(3);
    }
  
    @Test
    public void checkDisplayed_failsWhenNotExists() {
      Throwable thrown = catchThrowable(() -> assertDisplayed(R.id.no));
      assertThat(thrown).isInstanceOf(BaristaException.class)
          .hasMessageContaining("No view matching (view.getId() is <" + R.id.no + "/com.adevinta.android.barista.sample:id/no>) was found");
  
      Throwable thrown2 = catchThrowable(() -> assertDisplayed(R.string.not_exists));
      assertThat(thrown2).isInstanceOf(BaristaException.class)
          .hasMessage("No view matching (an instance of android.widget.TextView and view.getText() " +
              "equals string from resource id: <" + R.string.not_exists + "> [not_exists] value: Not exists) was found");
  
      Throwable thrown3 = catchThrowable(() -> assertDisplayed("Not exists"));
      assertThat(thrown3).isInstanceOf(BaristaException.class)
          .hasMessage("No view matching ((an instance of android.widget.TextView and view.getText()" +
              " with or without transformation to match: is \"Not exists\" or" +
              " (view.getParent() is assignable from class <class com.google.android.material.textfield.TextInputLayout>" +
              " and (view is an instance of android.view.ViewGroup and has descendant matching an instance of android.widget.TextView" +
              " and view.getText() with or without transformation to match: is \"Not exists\")))) was found");
  
      spyFailureHandlerRule.assertEspressoFailures(3);
    }
  
    @Test
    public void checkDisplayedIdAndText() {
      assertDisplayed(R.id.visible_view, "Hello world!");
      assertDisplayed(R.id.visible_view, R.string.hello_world);
  
      spyFailureHandlerRule.assertNoEspressoFailures();
    }
  
    @Test
    public void checkDisplayedIdAndText_failsWhenTextIsNotTheExpected() {
      Throwable thrown = catchThrowable(() -> assertDisplayed(R.id.visible_view, R.string.not_exists));
      assertThat(thrown).isInstanceOf(BaristaException.class)
          .hasMessage("View (view.getId() is <"
              + R.id.visible_view
              + "/com.adevinta.android.barista.sample:id/visible_view>) didn't match condition (((view has effective visibility <VISIBLE>"
              +
              " and view.getGlobalVisibleRect() to return non-empty rectangle) and an instance of android.widget.TextView and view.getText()"
              +
              " equals string from resource id: <"
              + R.string.not_exists
              + "> [not_exists] value: Not exists))");
  
      Throwable thrown2 = catchThrowable(() -> assertDisplayed(R.id.visible_view, "This is not the text you are looking for"));
      assertThat(thrown2).isInstanceOf(BaristaException.class)
          .hasMessage("View (view.getId() is <" + R.id.visible_view + "/com.adevinta.android.barista.sample:id/visible_view>)" +
              " didn't match condition (((view has effective visibility <VISIBLE> and view.getGlobalVisibleRect()" +
              " to return non-empty rectangle) and (an instance of android.widget.TextView and view.getText()" +
              " with or without transformation to match: is \"This is not the text you are looking for\"" +
              " or (view.getParent() is assignable from class <class com.google.android.material.textfield.TextInputLayout>" +
              " and (view is an instance of android.view.ViewGroup and has descendant matching an " +
              "instance of android.widget.TextView and view.getText() with or without transformation to match:" +
              " is \"This is not the text you are looking for\")))))");
  
      spyFailureHandlerRule.assertEspressoFailures(2);
    }
  
    @Test
    public void checkDisplayedIdAndText_failsWhenInvisible() {
      Throwable thrown = catchThrowable(() -> assertDisplayed(R.id.invisible_view, R.string.im_invisible));
      assertThat(thrown).isInstanceOf(BaristaException.class)
          .hasMessage("View (view.getId() is <" + R.id.invisible_view + "/com.adevinta.android.barista.sample:id/invisible_view>)" +
              " didn't match condition (((view has effective visibility <VISIBLE> and view.getGlobalVisibleRect()" +
              " to return non-empty rectangle) and an instance of android.widget.TextView and view.getText() " +
              "equals string from resource id: <" + R.string.im_invisible + ">))");
  
      Throwable thrown2 = catchThrowable(() -> assertDisplayed(R.id.invisible_view, "I'm invisible!"));
      assertThat(thrown2).isInstanceOf(BaristaException.class)
          .hasMessage("View (view.getId() is <" + R.id.invisible_view + "/com.adevinta.android.barista.sample:id/invisible_view>)" +
              " didn't match condition (((view has effective visibility <VISIBLE> and view.getGlobalVisibleRect()" +
              " to return non-empty rectangle) and (an instance of android.widget.TextView and view.getText()" +
              " with or without transformation to match: is \"I'm invisible!\"" +
              " or (view.getParent() is assignable from class <class com.google.android.material.textfield.TextInputLayout>" +
              " and (view is an instance of android.view.ViewGroup and has descendant matching an instance" +
              " of android.widget.TextView and view.getText() with or without transformation to match: is \"I'm invisible!\")))))");
  
      spyFailureHandlerRule.assertEspressoFailures(2);
    }
  
    @Test
    public void checkDisplayedIdAndText_failsWhenViewDoesNotExist() {
      Throwable thrown = catchThrowable(() -> assertDisplayed(R.id.not_exists, R.string.im_invisible));
      assertThat(thrown).isInstanceOf(BaristaException.class)
          .hasMessage("No view matching (view.getId() is <" + R.id.not_exists +
              "/com.adevinta.android.barista.sample:id/not_exists>) was found");
  
      Throwable thrown2 = catchThrowable(() -> assertDisplayed(R.id.not_exists, "This is not the text you are looking for"));
      assertThat(thrown2).isInstanceOf(BaristaException.class)
          .hasMessage(
              "No view matching (view.getId() is <" + R.id.not_exists + "/com.adevinta.android.barista.sample:id/not_exists>) was found");
  
      spyFailureHandlerRule.assertEspressoFailures(2);
    }
  
    @Test
    public void checkNotDisplayed_withInvisibleAndGoneViews() {
      assertNotDisplayed(R.id.invisible_view);
      assertNotDisplayed(R.id.gone_view);
      assertNotDisplayed(R.string.im_invisible);
      assertNotDisplayed("I'm invisible!");
  
      spyFailureHandlerRule.assertNoEspressoFailures();
    }
  
    @Test
    public void checkNotDisplayedIdAndText_whenTextDoesNotMatch() {
      assertNotDisplayed(R.id.visible_view, "This text must not be displayed on the view");
      assertNotDisplayed(R.id.visible_view, R.string.this_text_must_not_be_displayed);
  
      spyFailureHandlerRule.assertNoEspressoFailures();
    }
  
    @Test
    public void checkNotDisplayedIdAndText_failsWhenTextMatches() {
      Throwable thrown = catchThrowable(() -> assertNotDisplayed(R.id.visible_view, "Hello world!"));
  
      spyFailureHandlerRule.assertEspressoFailures(1);
      assertThat(thrown).isInstanceOf(BaristaException.class)
          .hasMessage("View (view.getId() is <" + R.id.visible_view + "/com.adevinta.android.barista.sample:id/visible_view>)" +
              " didn't match condition (not ((view has effective visibility <VISIBLE> and view.getGlobalVisibleRect()" +
              " to return non-empty rectangle) and (an instance of android.widget.TextView and view.getText()" +
              " with or without transformation to match: is \"Hello world!\" or" +
              " (view.getParent() is assignable from class <class com.google.android.material.textfield.TextInputLayout>" +
              " and (view is an instance of android.view.ViewGroup and has descendant matching an instance of" +
              " android.widget.TextView and view.getText() with or without transformation to match: is \"Hello world!\")))))");
    }
  
    @Test
    public void checkNotDisplayed_failsWhenVisible() {
      Throwable thrown = catchThrowable(() -> assertNotDisplayed(R.id.visible_view));
  
      spyFailureHandlerRule.assertEspressoFailures(1);
      assertThat(thrown).isInstanceOf(BaristaException.class)
          .hasMessage("View (view.getId() is <" + R.id.visible_view + "/com.adevinta.android.barista.sample:id/visible_view>)" +
              " didn't match condition (not (view has effective visibility <VISIBLE> and view.getGlobalVisibleRect()" +
              " to return non-empty rectangle))");
    }
  
    @Test
    public void checkNotExist() {
      assertNotExist(R.id.view_in_another_layout);
      assertNotExist(R.string.not_exists);
      assertNotExist("Unknown");
  
      spyFailureHandlerRule.assertNoEspressoFailures();
    }
  
    @Test
    public void checkNotExist_failsWhenViewExists() {
      Throwable thrown = catchThrowable(() -> assertNotExist(R.id.visible_view));
  
      spyFailureHandlerRule.assertEspressoFailures(1);
      assertThat(thrown).isInstanceOf(AssertionError.class)
          .hasMessageContaining("View is present in the hierarchy");
    }
  
    @Test
    public void assertVisibleWithCustomMatcher_Fails_WhenTheMatcherDoesNotFindTheGivenPredicate() {
      String aTagValueThatDoesNotExistsInTheView = "notPresentTagValue";
      Throwable thrown = catchThrowable(() ->
          assertDisplayed(withTagValue(is(aTagValueThatDoesNotExistsInTheView))));
  
      spyFailureHandlerRule.assertEspressoFailures(1);
      assertThat(thrown).isInstanceOf(BaristaException.class)
          .hasMessage("No view matching (view.getTag() is \"notPresentTagValue\") was found");
    }
  
    @Test
    public void assertVisibleWithCustomMatcher_Fails_WhenTheMatcherDoesFindTheGivenPredicateButViewIsHidden() {
      String nonExistingTag = "presentTagValueHidden";
      Throwable thrown = catchThrowable(() ->
          assertDisplayed(withTagValue(is(nonExistingTag))));
  
      spyFailureHandlerRule.assertEspressoFailures(1);
      assertThat(thrown).isInstanceOf(BaristaException.class)
          .hasMessage(
              "View (view.getTag() is \"presentTagValueHidden\") didn't match condition ((view has effective visibility <VISIBLE> and view.getGlobalVisibleRect() to return non-empty rectangle))");
    }
  
    @Test
    public void assertVisibleWithCustomMatcher_Succeeds_WhenTheMatcherMatchesAViewThatIsShown() {
      String existingTag = "presentTagValue";
  
      assertDisplayed(withTagValue(is(existingTag)));
  
      spyFailureHandlerRule.assertNoEspressoFailures();
    }
  
    @Test
    public void assertNotVisibleWithCustomMatcher_Fails_WhenTheMatcherDoesNotFindTheGivenPredicate() {
      String nonExistingTag = "notPresentTagValue";
  
      Throwable thrown = catchThrowable(() ->
          assertNotDisplayed(withTagValue(is(nonExistingTag))));
  
      spyFailureHandlerRule.assertEspressoFailures(1);
      assertThat(thrown).isInstanceOf(BaristaException.class)
          .hasMessage("No view matching (view.getTag() is \"notPresentTagValue\") was found");
    }
  
    @Test
    public void assertVisibleWithCustomMatcher_Succeeds_WhenTheMatcherMatchesAViewThatIsHidden() {
      String hiddenTag = "presentTagValueHidden";
  
      assertNotDisplayed(withTagValue(is(hiddenTag)));
  
      spyFailureHandlerRule.assertNoEspressoFailures();
    }
  
    @Test
    public void assertVisibleWithCustomMatcher_Fails_WhenTheMatcherMatchesAViewThatIsNotHidden() {
      String shownTag = "presentTagValue";
  
      Throwable thrown = catchThrowable(() ->
          assertNotDisplayed(withTagValue(is(shownTag))));
  
      spyFailureHandlerRule.assertEspressoFailures(1);
      String expectedMessage =
          "View (view.getTag() is \"presentTagValue\") didn't match condition" +
              " (not (view has effective visibility <VISIBLE> and view.getGlobalVisibleRect() to return non-empty rectangle))";
      assertThat(thrown).isInstanceOf(BaristaException.class).hasMessage(expectedMessage);
    }
  }
  