OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <map> | 5 #include <map> |
6 #include <string> | |
7 #include <vector> | |
6 | 8 |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
9 #include "base/location.h" | 11 #include "base/location.h" |
10 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
11 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
14 #include "base/strings/string_number_conversions.h" | |
12 #include "base/values.h" | 15 #include "base/values.h" |
13 #include "components/dom_distiller/core/distiller.h" | 16 #include "components/dom_distiller/core/distiller.h" |
14 #include "components/dom_distiller/core/distiller_page.h" | 17 #include "components/dom_distiller/core/distiller_page.h" |
18 #include "components/dom_distiller/core/proto/distilled_article.pb.h" | |
15 #include "components/dom_distiller/core/proto/distilled_page.pb.h" | 19 #include "components/dom_distiller/core/proto/distilled_page.pb.h" |
16 #include "net/url_request/url_request_context_getter.h" | 20 #include "net/url_request/url_request_context_getter.h" |
17 #include "testing/gmock/include/gmock/gmock.h" | 21 #include "testing/gmock/include/gmock/gmock.h" |
18 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
19 | 23 |
24 using std::vector; | |
25 using std::string; | |
20 using::testing::Invoke; | 26 using::testing::Invoke; |
21 using::testing::Return; | 27 using::testing::Return; |
22 using::testing::_; | 28 using::testing::_; |
23 | 29 |
24 namespace { | 30 namespace { |
25 const char kTitle[] = "Title"; | 31 const char kTitle[] = "Title"; |
26 const char kContent[] = "Content"; | 32 const char kContent[] = "Content"; |
27 const char kURL[] = "http://a.com/"; | 33 const char kURL[] = "http://a.com/"; |
28 const char kId0[] = "0"; | 34 const size_t kTotalImages = 2; |
29 const char kId1[] = "1"; | 35 const char* kImageURLs[kTotalImages] = {"http://a.com/img1.jpg", |
30 const char kImageURL0[] = "http://a.com/img1.jpg"; | 36 "http://a.com/img2.jpg"}; |
31 const char kImageURL1[] = "http://a.com/img2.jpg"; | 37 const char* kImageData[kTotalImages] = {"abcde", "12345"}; |
32 const char kImageData0[] = { 'a', 'b', 'c', 'd', 'e', 0 }; | 38 |
33 const char kImageData1[] = { '1', '2', '3', '4', '5', 0 }; | 39 const string GetImageName(int page_num, int image_num) { |
40 return base::IntToString(page_num) + "_" + base::IntToString(image_num); | |
41 } | |
42 | |
43 scoped_ptr<base::ListValue> CreateDistilledValueReturnedFromJS( | |
44 const string& title, | |
45 const string& content, | |
46 const vector<int>& image_indices, | |
47 const string& next_page_url) { | |
48 scoped_ptr<base::ListValue> list(new base::ListValue()); | |
49 | |
50 list->AppendString(title); | |
51 list->AppendString(content); | |
52 list->AppendString(next_page_url); | |
53 for (size_t i = 0; i < image_indices.size(); ++i) { | |
54 list->AppendString(kImageURLs[image_indices[i]]); | |
55 } | |
56 return list.Pass(); | |
57 } | |
58 | |
34 } // namespace | 59 } // namespace |
35 | 60 |
36 namespace dom_distiller { | 61 namespace dom_distiller { |
37 | 62 |
38 class TestDistillerURLFetcher : public DistillerURLFetcher { | 63 class TestDistillerURLFetcher : public DistillerURLFetcher { |
39 public: | 64 public: |
40 TestDistillerURLFetcher() : DistillerURLFetcher(NULL) { | 65 TestDistillerURLFetcher() : DistillerURLFetcher(NULL) { |
41 responses_[kImageURL0] = std::string(kImageData0); | 66 responses_[kImageURLs[0]] = string(kImageData[0]); |
42 responses_[kImageURL1] = std::string(kImageData1); | 67 responses_[kImageURLs[1]] = string(kImageData[1]); |
43 } | 68 } |
44 | 69 |
45 void CallCallback(std::string url, const URLFetcherCallback& callback) { | 70 void CallCallback(string url, const URLFetcherCallback& callback) { |
46 callback.Run(responses_[url]); | 71 callback.Run(responses_[url]); |
47 } | 72 } |
48 | 73 |
49 virtual void FetchURL(const std::string& url, | 74 virtual void FetchURL(const string& url, |
50 const URLFetcherCallback& callback) OVERRIDE { | 75 const URLFetcherCallback& callback) OVERRIDE { |
51 ASSERT_TRUE(base::MessageLoop::current()); | 76 ASSERT_TRUE(base::MessageLoop::current()); |
52 base::MessageLoop::current()->PostTask( | 77 base::MessageLoop::current()->PostTask( |
53 FROM_HERE, | 78 FROM_HERE, |
54 base::Bind(&TestDistillerURLFetcher::CallCallback, | 79 base::Bind(&TestDistillerURLFetcher::CallCallback, |
55 base::Unretained(this), url, callback)); | 80 base::Unretained(this), url, callback)); |
56 } | 81 } |
57 | 82 |
58 std::map<std::string, std::string> responses_; | 83 std::map<string, string> responses_; |
59 }; | 84 }; |
60 | 85 |
61 | 86 |
62 class TestDistillerURLFetcherFactory : public DistillerURLFetcherFactory { | 87 class TestDistillerURLFetcherFactory : public DistillerURLFetcherFactory { |
63 public: | 88 public: |
64 TestDistillerURLFetcherFactory() : DistillerURLFetcherFactory(NULL) {} | 89 TestDistillerURLFetcherFactory() : DistillerURLFetcherFactory(NULL) {} |
65 virtual ~TestDistillerURLFetcherFactory() {} | 90 virtual ~TestDistillerURLFetcherFactory() {} |
66 virtual DistillerURLFetcher* CreateDistillerURLFetcher() const OVERRIDE { | 91 virtual DistillerURLFetcher* CreateDistillerURLFetcher() const OVERRIDE { |
67 return new TestDistillerURLFetcher(); | 92 return new TestDistillerURLFetcher(); |
68 } | 93 } |
69 }; | 94 }; |
70 | 95 |
71 | 96 |
72 class MockDistillerPage : public DistillerPage { | 97 class MockDistillerPage : public DistillerPage { |
73 public: | 98 public: |
74 MOCK_METHOD0(InitImpl, void()); | 99 MOCK_METHOD0(InitImpl, void()); |
75 MOCK_METHOD1(LoadURLImpl, void(const GURL& gurl)); | 100 MOCK_METHOD1(LoadURLImpl, void(const GURL& gurl)); |
76 MOCK_METHOD1(ExecuteJavaScriptImpl, void(const std::string& script)); | 101 MOCK_METHOD1(ExecuteJavaScriptImpl, void(const string& script)); |
77 | 102 |
78 explicit MockDistillerPage(DistillerPage::Delegate* delegate) | 103 explicit MockDistillerPage(DistillerPage::Delegate* delegate) |
79 : DistillerPage(delegate) {} | 104 : DistillerPage(delegate) {} |
80 }; | 105 }; |
81 | 106 |
82 | 107 |
83 class MockDistillerPageFactory : public DistillerPageFactory { | 108 class MockDistillerPageFactory : public DistillerPageFactory { |
84 public: | 109 public: |
85 MOCK_CONST_METHOD1( | 110 MOCK_CONST_METHOD1( |
86 CreateDistillerPageMock, | 111 CreateDistillerPageMock, |
87 DistillerPage*(DistillerPage::Delegate* delegate)); | 112 DistillerPage*(DistillerPage::Delegate* delegate)); |
88 | 113 |
89 virtual scoped_ptr<DistillerPage> CreateDistillerPage( | 114 virtual scoped_ptr<DistillerPage> CreateDistillerPage( |
90 DistillerPage::Delegate* delegate) const OVERRIDE { | 115 DistillerPage::Delegate* delegate) const OVERRIDE { |
91 return scoped_ptr<DistillerPage>(CreateDistillerPageMock(delegate)); | 116 return scoped_ptr<DistillerPage>(CreateDistillerPageMock(delegate)); |
92 } | 117 } |
93 }; | 118 }; |
94 | 119 |
95 | 120 |
96 class DistillerTest : public testing::Test { | 121 class DistillerTest : public testing::Test { |
97 public: | 122 public: |
98 virtual ~DistillerTest() {} | 123 virtual ~DistillerTest() {} |
99 void OnDistillPageDone(scoped_ptr<DistilledPageProto> proto) { | 124 void OnDistillPageDone(scoped_ptr<DistilledArticleProto> proto) { |
100 proto_ = proto.Pass(); | 125 article_proto_ = proto.Pass(); |
101 } | 126 } |
102 | 127 |
103 protected: | 128 protected: |
104 scoped_ptr<DistillerImpl> distiller_; | 129 scoped_ptr<DistillerImpl> distiller_; |
105 scoped_ptr<DistilledPageProto> proto_; | 130 scoped_ptr<DistilledArticleProto> article_proto_; |
106 MockDistillerPageFactory page_factory_; | 131 MockDistillerPageFactory page_factory_; |
107 TestDistillerURLFetcherFactory url_fetcher_factory_; | 132 TestDistillerURLFetcherFactory url_fetcher_factory_; |
108 }; | 133 }; |
109 | 134 |
110 ACTION_P2(DistillerPageOnExecuteJavaScriptDone, distiller_page, list) { | 135 ACTION_P3(DistillerPageOnExecuteJavaScriptDone, distiller_page, url, list) { |
111 distiller_page->OnExecuteJavaScriptDone(list); | 136 distiller_page->OnExecuteJavaScriptDone(url, list); |
112 } | 137 } |
113 | 138 |
114 ACTION_P2(CreateMockDistillerPage, list, kurl) { | 139 ACTION_P2(CreateMockDistillerPage, list, kurl) { |
115 DistillerPage::Delegate* delegate = arg0; | 140 DistillerPage::Delegate* delegate = arg0; |
116 MockDistillerPage* distiller_page = new MockDistillerPage(delegate); | 141 MockDistillerPage* distiller_page = new MockDistillerPage(delegate); |
117 EXPECT_CALL(*distiller_page, InitImpl()); | 142 EXPECT_CALL(*distiller_page, InitImpl()); |
118 EXPECT_CALL(*distiller_page, LoadURLImpl(kurl)) | 143 EXPECT_CALL(*distiller_page, LoadURLImpl(kurl)) |
119 .WillOnce(testing::InvokeWithoutArgs(distiller_page, | 144 .WillOnce(testing::InvokeWithoutArgs(distiller_page, |
120 &DistillerPage::OnLoadURLDone)); | 145 &DistillerPage::OnLoadURLDone)); |
121 EXPECT_CALL(*distiller_page, ExecuteJavaScriptImpl(_)) | 146 EXPECT_CALL(*distiller_page, ExecuteJavaScriptImpl(_)).WillOnce( |
122 .WillOnce(DistillerPageOnExecuteJavaScriptDone(distiller_page, list)); | 147 DistillerPageOnExecuteJavaScriptDone(distiller_page, kurl, list)); |
148 return distiller_page; | |
149 } | |
150 | |
151 ACTION_P3(CreateMockDistillerPages, lists, kurls, num_pages) { | |
152 DistillerPage::Delegate* delegate = arg0; | |
153 MockDistillerPage* distiller_page = new MockDistillerPage(delegate); | |
154 EXPECT_CALL(*distiller_page, InitImpl()); | |
155 { | |
156 testing::InSequence s; | |
157 | |
158 for (int page = 0; page < num_pages; ++page) { | |
159 GURL url = GURL(kurls[page]); | |
160 EXPECT_CALL(*distiller_page, LoadURLImpl(url)) | |
161 .WillOnce(testing::InvokeWithoutArgs(distiller_page, | |
162 &DistillerPage::OnLoadURLDone)); | |
163 EXPECT_CALL(*distiller_page, ExecuteJavaScriptImpl(_)) | |
164 .WillOnce(DistillerPageOnExecuteJavaScriptDone( | |
165 distiller_page, url, lists[page].get())); | |
166 } | |
167 } | |
123 return distiller_page; | 168 return distiller_page; |
124 } | 169 } |
125 | 170 |
126 TEST_F(DistillerTest, DistillPage) { | 171 TEST_F(DistillerTest, DistillPage) { |
127 base::MessageLoopForUI loop; | 172 base::MessageLoopForUI loop; |
128 scoped_ptr<base::ListValue> list(new base::ListValue()); | 173 vector<int> image_indices; |
cjhopman
2014/02/03 21:47:22
Could we have a test for distilling a page with no
shashi
2014/02/03 23:19:29
Done.
| |
129 list->AppendString(kTitle); | 174 image_indices.push_back(0); |
130 list->AppendString(kContent); | 175 image_indices.push_back(1); |
131 list->AppendString(kImageURL0); | 176 scoped_ptr<base::ListValue> list = |
132 list->AppendString(kImageURL1); | 177 CreateDistilledValueReturnedFromJS(kTitle, kContent, image_indices, ""); |
133 EXPECT_CALL(page_factory_, | 178 EXPECT_CALL(page_factory_, |
134 CreateDistillerPageMock(_)).WillOnce( | 179 CreateDistillerPageMock(_)).WillOnce( |
135 CreateMockDistillerPage(list.get(), GURL(kURL))); | 180 CreateMockDistillerPage(list.get(), GURL(kURL))); |
136 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | 181 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
137 distiller_->Init(); | 182 distiller_->Init(); |
138 distiller_->DistillPage( | 183 distiller_->DistillPage( |
139 GURL(kURL), | 184 GURL(kURL), |
140 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | 185 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); |
141 base::MessageLoop::current()->RunUntilIdle(); | 186 base::MessageLoop::current()->RunUntilIdle(); |
142 EXPECT_EQ(kTitle, proto_->title()); | 187 EXPECT_EQ(kTitle, article_proto_->title()); |
143 EXPECT_EQ(kContent, proto_->html()); | 188 EXPECT_EQ(article_proto_->pages_size(), 1); |
144 EXPECT_EQ(kURL, proto_->url()); | 189 const DistilledPageProto& first_page = article_proto_->pages(0); |
145 EXPECT_EQ(2, proto_->image_size()); | 190 EXPECT_EQ(kContent, first_page.html()); |
146 EXPECT_EQ(kImageData0, proto_->image(0).data()); | 191 EXPECT_EQ(kURL, first_page.url()); |
147 EXPECT_EQ(kId0, proto_->image(0).name()); | 192 EXPECT_EQ(2, first_page.image_size()); |
148 EXPECT_EQ(kImageData1, proto_->image(1).data()); | 193 EXPECT_EQ(kImageData[0], first_page.image(0).data()); |
149 EXPECT_EQ(kId1, proto_->image(1).name()); | 194 EXPECT_EQ(GetImageName(1, 0), first_page.image(0).name()); |
195 EXPECT_EQ(kImageData[1], first_page.image(1).data()); | |
196 EXPECT_EQ(GetImageName(1, 1), first_page.image(1).name()); | |
197 } | |
198 | |
199 TEST_F(DistillerTest, DistillMultiplePages) { | |
200 base::MessageLoopForUI loop; | |
201 const int kNumPages = 8; | |
202 vector<int> image_indices[kNumPages]; | |
203 string content[kNumPages]; | |
204 string page_urls[kNumPages]; | |
205 scoped_ptr<base::ListValue> list[kNumPages]; | |
206 | |
207 int next_image_number = 0; | |
208 | |
209 for (int page_num = 0; page_num < kNumPages; ++page_num) { | |
210 // Each page has different number of images. | |
211 int tot_images = (page_num + kTotalImages) % (kTotalImages + 1); | |
212 for (int img_num = 0; img_num < tot_images; img_num++) { | |
213 image_indices[page_num].push_back(next_image_number); | |
214 next_image_number = (next_image_number + 1) % kTotalImages; | |
215 } | |
216 | |
217 page_urls[page_num] = "http://a.com/" + base::IntToString(page_num); | |
218 content[page_num] = "Content for page:" + base::IntToString(page_num); | |
219 } | |
220 for (int i = 0; i < kNumPages; ++i) { | |
221 string next_page_url = ""; | |
222 if (i + 1 < kNumPages) | |
223 next_page_url = page_urls[i + 1]; | |
224 | |
225 list[i] = CreateDistilledValueReturnedFromJS( | |
226 kTitle, content[i], image_indices[i], next_page_url); | |
227 } | |
228 | |
229 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) | |
230 .WillOnce(CreateMockDistillerPages(list, page_urls, kNumPages)); | |
231 | |
232 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | |
233 distiller_->Init(); | |
234 distiller_->DistillPage( | |
235 GURL(page_urls[0]), | |
236 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | |
237 base::MessageLoop::current()->RunUntilIdle(); | |
238 EXPECT_EQ(kTitle, article_proto_->title()); | |
239 EXPECT_EQ(article_proto_->pages_size(), kNumPages); | |
240 for (int page_num = 0; page_num < kNumPages; ++page_num) { | |
241 const DistilledPageProto& page = article_proto_->pages(page_num); | |
242 EXPECT_EQ(content[page_num], page.html()); | |
243 EXPECT_EQ(page_urls[page_num], page.url()); | |
244 EXPECT_EQ(image_indices[page_num].size(), | |
245 static_cast<size_t>(page.image_size())); | |
246 for (size_t img_num = 0; img_num < image_indices[page_num].size(); | |
247 ++img_num) { | |
248 EXPECT_EQ(kImageData[image_indices[page_num][img_num]], | |
249 page.image(img_num).data()); | |
250 EXPECT_EQ(GetImageName(page_num + 1, img_num), | |
251 page.image(img_num).name()); | |
252 } | |
253 } | |
254 } | |
255 | |
256 TEST_F(DistillerTest, DistillLinkLoop) { | |
257 base::MessageLoopForUI loop; | |
258 vector<int> image_indices; | |
cjhopman
2014/02/03 21:47:22
Don't have images here if they aren't needed for t
shashi
2014/02/03 23:19:29
Done.
| |
259 image_indices.push_back(0); | |
260 image_indices.push_back(1); | |
261 // Create a loop, the next page is same as the current page. This could | |
262 // happen if javascript misparses a next page link. | |
263 scoped_ptr<base::ListValue> list = | |
264 CreateDistilledValueReturnedFromJS(kTitle, kContent, image_indices, kURL); | |
265 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) | |
266 .WillOnce(CreateMockDistillerPage(list.get(), GURL(kURL))); | |
267 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | |
268 distiller_->Init(); | |
269 distiller_->DistillPage( | |
270 GURL(kURL), | |
271 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | |
272 base::MessageLoop::current()->RunUntilIdle(); | |
273 EXPECT_EQ(kTitle, article_proto_->title()); | |
274 EXPECT_EQ(article_proto_->pages_size(), 1); | |
150 } | 275 } |
151 | 276 |
152 } // namespace dom_distiller | 277 } // namespace dom_distiller |
OLD | NEW |