page_annotator_unittest.cc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/page_image_annotation/core/page_annotator.h"
  5. #include <vector>
  6. #include "base/bind.h"
  7. #include "base/test/task_environment.h"
  8. #include "mojo/public/cpp/bindings/pending_remote.h"
  9. #include "mojo/public/cpp/bindings/receiver_set.h"
  10. #include "mojo/public/cpp/bindings/remote.h"
  11. #include "testing/gmock/include/gmock/gmock.h"
  12. #include "testing/gtest/include/gtest/gtest.h"
  13. namespace page_image_annotation {
  14. namespace {
  15. namespace ia_mojom = image_annotation::mojom;
  16. using testing::ElementsAre;
  17. using testing::Eq;
  18. using testing::NiceMock;
  19. using testing::SizeIs;
  20. // A gMock matcher that compares an ImageMetadata to the given node and source
  21. // IDs.
  22. MATCHER_P2(IsImageMetadata, expected_node_id, expected_source_id, "") {
  23. return arg.node_id == expected_node_id && arg.source_id == expected_source_id;
  24. }
  25. // A gMock matcher that (deep) compares an AnnotateImageResultPtr to the
  26. // expected result (which is of type AnnotateImageResult*).
  27. MATCHER_P(IsAnnotateImageResult, expected, "") {
  28. return arg->Equals(*expected);
  29. }
  30. class MockObserver : public PageAnnotator::Observer {
  31. public:
  32. MOCK_METHOD1(OnImageAdded,
  33. void(const PageAnnotator::ImageMetadata& metadata));
  34. MOCK_METHOD1(OnImageModified,
  35. void(const PageAnnotator::ImageMetadata& metadata));
  36. MOCK_METHOD1(OnImageRemoved, void(uint64_t node_id));
  37. MOCK_METHOD2(OnImageAnnotated,
  38. void(uint64_t node_id, ia_mojom::AnnotateImageResultPtr result));
  39. };
  40. // An annotator that just stores and exposes the arguments with which its
  41. // AnnotateImage method was called.
  42. class TestAnnotator : public ia_mojom::Annotator {
  43. public:
  44. mojo::PendingRemote<ia_mojom::Annotator> GetRemote() {
  45. mojo::PendingRemote<ia_mojom::Annotator> remote;
  46. receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver());
  47. return remote;
  48. }
  49. void AnnotateImage(
  50. const std::string& source_id,
  51. const std::string& description_language_tag,
  52. mojo::PendingRemote<ia_mojom::ImageProcessor> image_processor,
  53. AnnotateImageCallback callback) override {
  54. CHECK_EQ(description_language_tag, std::string());
  55. source_ids_.push_back(source_id);
  56. image_processors_.push_back(
  57. mojo::Remote<ia_mojom::ImageProcessor>(std::move(image_processor)));
  58. image_processors_.back().set_disconnect_handler(
  59. base::BindOnce(&TestAnnotator::ResetImageProcessor,
  60. base::Unretained(this), image_processors_.size() - 1));
  61. callbacks_.push_back(std::move(callback));
  62. }
  63. // Tests should not delete entries in these lists.
  64. std::vector<std::string> source_ids_;
  65. std::vector<mojo::Remote<ia_mojom::ImageProcessor>> image_processors_;
  66. std::vector<AnnotateImageCallback> callbacks_;
  67. private:
  68. void ResetImageProcessor(const size_t index) {
  69. image_processors_[index].reset();
  70. }
  71. mojo::ReceiverSet<ia_mojom::Annotator> receivers_;
  72. };
  73. // Tests that correct image tracking messages are sent to observers.
  74. TEST(PageAnnotatorTest, ImageTracking) {
  75. const auto get_pixels = base::BindRepeating([]() { return SkBitmap(); });
  76. base::test::TaskEnvironment test_task_env;
  77. PageAnnotator page_annotator((mojo::NullRemote()));
  78. MockObserver o1;
  79. page_annotator.AddObserver(&o1);
  80. EXPECT_CALL(o1, OnImageAdded(IsImageMetadata(1ul, "test.jpg")));
  81. page_annotator.ImageAddedOrPossiblyModified({1ul, "test.jpg"}, get_pixels);
  82. EXPECT_CALL(o1, OnImageAdded(IsImageMetadata(2ul, "example.png")));
  83. page_annotator.ImageAddedOrPossiblyModified({2ul, "example.png"}, get_pixels);
  84. EXPECT_CALL(o1, OnImageModified(IsImageMetadata(1ul, "demo.gif")));
  85. page_annotator.ImageAddedOrPossiblyModified({1ul, "demo.gif"}, get_pixels);
  86. EXPECT_CALL(o1, OnImageRemoved(2ul));
  87. page_annotator.ImageRemoved(2ul);
  88. MockObserver o2;
  89. EXPECT_CALL(o2, OnImageAdded(IsImageMetadata(1ul, "demo.gif")));
  90. page_annotator.AddObserver(&o2);
  91. }
  92. // Tests service and observer communication when performing image annotation.
  93. TEST(PageAnnotatorTest, Annotation) {
  94. // Returning a null SkBitmap is ok as long as we don't request JPG data from
  95. // the local ImageProcessor.
  96. const auto get_pixels = base::BindRepeating([]() { return SkBitmap(); });
  97. base::test::TaskEnvironment test_task_env;
  98. TestAnnotator test_annotator;
  99. PageAnnotator page_annotator(test_annotator.GetRemote());
  100. test_task_env.RunUntilIdle();
  101. // We use NiceMocks here since we don't place expectations on image added /
  102. // removed calls, which will otherwise cause many (benign) warnings to be
  103. // logged.
  104. NiceMock<MockObserver> o1, o2;
  105. page_annotator.AddObserver(&o1);
  106. page_annotator.AddObserver(&o2);
  107. // First image added.
  108. page_annotator.ImageAddedOrPossiblyModified({1ul, "test.jpg"}, get_pixels);
  109. // Observer 1 requests annotation of the first image.
  110. page_annotator.AnnotateImage(&o1, 1ul);
  111. test_task_env.RunUntilIdle();
  112. // The annotator should have been provided observer 1's request info.
  113. EXPECT_THAT(test_annotator.source_ids_, ElementsAre("test.jpg"));
  114. ASSERT_THAT(test_annotator.image_processors_, SizeIs(1));
  115. EXPECT_THAT(test_annotator.image_processors_[0].is_bound(), Eq(true));
  116. EXPECT_THAT(test_annotator.callbacks_, SizeIs(1));
  117. // Observer 2 requests annotation of the same image.
  118. page_annotator.AnnotateImage(&o2, 1ul);
  119. test_task_env.RunUntilIdle();
  120. // The annotator should have been provided observer 2's request info.
  121. EXPECT_THAT(test_annotator.source_ids_, ElementsAre("test.jpg", "test.jpg"));
  122. ASSERT_THAT(test_annotator.image_processors_, SizeIs(2));
  123. EXPECT_THAT(test_annotator.image_processors_[0].is_bound(), Eq(true));
  124. EXPECT_THAT(test_annotator.image_processors_[1].is_bound(), Eq(true));
  125. EXPECT_THAT(test_annotator.callbacks_, SizeIs(2));
  126. // Second image added.
  127. page_annotator.ImageAddedOrPossiblyModified({2ul, "example.png"}, get_pixels);
  128. // Observer 2 requests annotation of the second image.
  129. page_annotator.AnnotateImage(&o2, 2ul);
  130. test_task_env.RunUntilIdle();
  131. // All three requests should have been provided to the annotator.
  132. EXPECT_THAT(test_annotator.source_ids_,
  133. ElementsAre("test.jpg", "test.jpg", "example.png"));
  134. ASSERT_THAT(test_annotator.image_processors_, SizeIs(3));
  135. EXPECT_THAT(test_annotator.image_processors_[0].is_bound(), Eq(true));
  136. EXPECT_THAT(test_annotator.image_processors_[1].is_bound(), Eq(true));
  137. EXPECT_THAT(test_annotator.image_processors_[2].is_bound(), Eq(true));
  138. EXPECT_THAT(test_annotator.callbacks_, SizeIs(3));
  139. // Image 1 goes away.
  140. page_annotator.ImageRemoved(1ul);
  141. test_task_env.RunUntilIdle();
  142. // The corresponding image processors should have been disconnected.
  143. ASSERT_THAT(test_annotator.image_processors_, SizeIs(3));
  144. EXPECT_THAT(test_annotator.image_processors_[0].is_bound(), Eq(false));
  145. EXPECT_THAT(test_annotator.image_processors_[1].is_bound(), Eq(false));
  146. EXPECT_THAT(test_annotator.image_processors_[2].is_bound(), Eq(true));
  147. // Expect success and failure to be reported.
  148. const auto error = ia_mojom::AnnotateImageResult::NewErrorCode(
  149. ia_mojom::AnnotateImageError::kCanceled);
  150. // Can't use an initializer list since it performs copies.
  151. std::vector<ia_mojom::AnnotationPtr> annotations;
  152. annotations.push_back(ia_mojom::Annotation::New(
  153. ia_mojom::AnnotationType::kOcr, 1.0, "text from image"));
  154. const auto success =
  155. ia_mojom::AnnotateImageResult::NewAnnotations(std::move(annotations));
  156. ASSERT_THAT(test_annotator.callbacks_, SizeIs(3));
  157. std::move(test_annotator.callbacks_[0]).Run(error.Clone());
  158. std::move(test_annotator.callbacks_[1]).Run(error.Clone());
  159. std::move(test_annotator.callbacks_[2]).Run(success.Clone());
  160. EXPECT_CALL(o1, OnImageAnnotated(1ul, IsAnnotateImageResult(error.get())));
  161. EXPECT_CALL(o2, OnImageAnnotated(1ul, IsAnnotateImageResult(error.get())));
  162. EXPECT_CALL(o2, OnImageAnnotated(2ul, IsAnnotateImageResult(success.get())));
  163. test_task_env.RunUntilIdle();
  164. }
  165. } // namespace
  166. } // namespace page_image_annotation