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 <algorithm> |
5 #include <map> | 6 #include <map> |
6 #include <string> | 7 #include <string> |
7 #include <vector> | 8 #include <vector> |
8 | 9 |
9 #include "base/bind.h" | 10 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
11 #include "base/location.h" | 12 #include "base/location.h" |
12 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
13 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
14 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
15 #include "base/values.h" | 16 #include "base/values.h" |
| 17 #include "components/dom_distiller/core/article_distillation_update.h" |
16 #include "components/dom_distiller/core/distiller.h" | 18 #include "components/dom_distiller/core/distiller.h" |
17 #include "components/dom_distiller/core/distiller_page.h" | 19 #include "components/dom_distiller/core/distiller_page.h" |
18 #include "components/dom_distiller/core/proto/distilled_article.pb.h" | 20 #include "components/dom_distiller/core/proto/distilled_article.pb.h" |
19 #include "components/dom_distiller/core/proto/distilled_page.pb.h" | 21 #include "components/dom_distiller/core/proto/distilled_page.pb.h" |
20 #include "net/url_request/url_request_context_getter.h" | 22 #include "net/url_request/url_request_context_getter.h" |
21 #include "testing/gmock/include/gmock/gmock.h" | 23 #include "testing/gmock/include/gmock/gmock.h" |
22 #include "testing/gtest/include/gtest/gtest.h" | 24 #include "testing/gtest/include/gtest/gtest.h" |
23 | 25 |
24 using std::vector; | 26 using std::vector; |
25 using std::string; | 27 using std::string; |
26 using::testing::Invoke; | 28 using ::testing::Invoke; |
27 using::testing::Return; | 29 using ::testing::Return; |
28 using::testing::_; | 30 using ::testing::_; |
29 | 31 |
30 namespace { | 32 namespace { |
31 const char kTitle[] = "Title"; | 33 const char kTitle[] = "Title"; |
32 const char kContent[] = "Content"; | 34 const char kContent[] = "Content"; |
33 const char kURL[] = "http://a.com/"; | 35 const char kURL[] = "http://a.com/"; |
34 const size_t kTotalImages = 2; | 36 const size_t kTotalImages = 2; |
35 const char* kImageURLs[kTotalImages] = {"http://a.com/img1.jpg", | 37 const char* kImageURLs[kTotalImages] = {"http://a.com/img1.jpg", |
36 "http://a.com/img2.jpg"}; | 38 "http://a.com/img2.jpg"}; |
37 const char* kImageData[kTotalImages] = {"abcde", "12345"}; | 39 const char* kImageData[kTotalImages] = {"abcde", "12345"}; |
38 | 40 |
39 const string GetImageName(int page_num, int image_num) { | 41 const string GetImageName(int page_num, int image_num) { |
40 return base::IntToString(page_num) + "_" + base::IntToString(image_num); | 42 return base::IntToString(page_num) + "_" + base::IntToString(image_num); |
| 43 } |
| 44 |
| 45 scoped_ptr<base::ListValue> CreateDistilledValueReturnedFromJS( |
| 46 const string& title, |
| 47 const string& content, |
| 48 const vector<int>& image_indices, |
| 49 const string& next_page_url, |
| 50 const string& prev_page_url = "") { |
| 51 scoped_ptr<base::ListValue> list(new base::ListValue()); |
| 52 |
| 53 list->AppendString(title); |
| 54 list->AppendString(content); |
| 55 list->AppendString(next_page_url); |
| 56 list->AppendString(prev_page_url); |
| 57 for (size_t i = 0; i < image_indices.size(); ++i) { |
| 58 list->AppendString(kImageURLs[image_indices[i]]); |
41 } | 59 } |
| 60 return list.Pass(); |
| 61 } |
42 | 62 |
43 scoped_ptr<base::ListValue> CreateDistilledValueReturnedFromJS( | 63 // Return the sequence in which Distiller will distill pages. |
44 const string& title, | 64 // Note: ignores any delays due to fetching images etc. |
45 const string& content, | 65 vector<int> GetPagesInSequence(int start_page_num, int num_pages) { |
46 const vector<int>& image_indices, | 66 // Distiller prefers distilling past pages first. E.g. when distillation |
47 const string& next_page_url, | 67 // starts on page 2 then pages are distilled in the order: 2, 1, 0, 3, 4. |
48 const string& prev_page_url = "") { | 68 vector<int> page_nums; |
49 scoped_ptr<base::ListValue> list(new base::ListValue()); | 69 for (int page = start_page_num; page >= 0; --page) |
| 70 page_nums.push_back(page); |
| 71 for (int page = start_page_num + 1; page < num_pages; ++page) |
| 72 page_nums.push_back(page); |
| 73 return page_nums; |
| 74 } |
50 | 75 |
51 list->AppendString(title); | 76 struct MultipageDistillerData { |
52 list->AppendString(content); | 77 public: |
53 list->AppendString(next_page_url); | 78 MultipageDistillerData() {} |
54 list->AppendString(prev_page_url); | 79 ~MultipageDistillerData() {} |
55 for (size_t i = 0; i < image_indices.size(); ++i) { | 80 vector<string> page_urls; |
56 list->AppendString(kImageURLs[image_indices[i]]); | 81 vector<string> content; |
| 82 vector<vector<int> > image_ids; |
| 83 // The Javascript values returned by mock distiller. |
| 84 ScopedVector<base::Value> distilled_values; |
| 85 |
| 86 private: |
| 87 DISALLOW_COPY_AND_ASSIGN(MultipageDistillerData); |
| 88 }; |
| 89 |
| 90 void VerifyIncrementalUpdatesMatch( |
| 91 const MultipageDistillerData* distiller_data, |
| 92 int num_pages_in_article, |
| 93 const vector<dom_distiller::ArticleDistillationUpdate>& incremental_updates, |
| 94 int start_page_num) { |
| 95 vector<int> page_seq = |
| 96 GetPagesInSequence(start_page_num, num_pages_in_article); |
| 97 // Updates should contain a list of pages. Pages in an update should be in |
| 98 // the correct ascending page order regardless of |start_page_num|. |
| 99 // E.g. if distillation starts at page 2 of a 3 page article, the updates |
| 100 // will be [[2], [1, 2], [1, 2, 3]]. This example assumes that image fetches |
| 101 // do not delay distillation of a page. There can be scenarios when image |
| 102 // fetch delays distillation of a page (E.g. 1 is delayed due to image |
| 103 // fetches so updates can be in this order [[2], [2,3], [1,2,3]]. |
| 104 for (size_t update_count = 0; update_count < incremental_updates.size(); |
| 105 ++update_count) { |
| 106 const dom_distiller::ArticleDistillationUpdate& update = |
| 107 incremental_updates[update_count]; |
| 108 EXPECT_EQ(update_count + 1, update.GetPagesSize()); |
| 109 |
| 110 vector<int> expected_page_nums_in_update( |
| 111 page_seq.begin(), page_seq.begin() + update.GetPagesSize()); |
| 112 std::sort(expected_page_nums_in_update.begin(), |
| 113 expected_page_nums_in_update.end()); |
| 114 |
| 115 // If we already got the first page then there is no previous page. |
| 116 EXPECT_EQ((expected_page_nums_in_update[0] != 0), update.HasPrevPage()); |
| 117 |
| 118 // if we already got the last page then there is no next page. |
| 119 EXPECT_EQ( |
| 120 (*expected_page_nums_in_update.rbegin()) != num_pages_in_article - 1, |
| 121 update.HasNextPage()); |
| 122 for (size_t j = 0; j < update.GetPagesSize(); ++j) { |
| 123 int actual_page_num = expected_page_nums_in_update[j]; |
| 124 EXPECT_EQ(distiller_data->page_urls[actual_page_num], |
| 125 update.GetDistilledPage(j).url()); |
| 126 EXPECT_EQ(distiller_data->content[actual_page_num], |
| 127 update.GetDistilledPage(j).html()); |
57 } | 128 } |
58 return list.Pass(); | |
59 } | 129 } |
| 130 } |
| 131 |
| 132 scoped_ptr<MultipageDistillerData> CreateMultipageDistillerDataWithoutImages( |
| 133 size_t pages_size) { |
| 134 scoped_ptr<MultipageDistillerData> result(new MultipageDistillerData()); |
| 135 string url_prefix = "http://a.com/"; |
| 136 for (size_t page_num = 0; page_num < pages_size; ++page_num) { |
| 137 result->page_urls.push_back(url_prefix + base::IntToString(page_num)); |
| 138 result->content.push_back("Content for page:" + |
| 139 base::IntToString(page_num)); |
| 140 result->image_ids.push_back(vector<int>()); |
| 141 string next_page_url = (page_num + 1 < pages_size) |
| 142 ? url_prefix + base::IntToString(page_num + 1) |
| 143 : ""; |
| 144 string prev_page_url = |
| 145 (page_num > 0) ? result->page_urls[page_num - 1] : ""; |
| 146 scoped_ptr<base::ListValue> distilled_value = |
| 147 CreateDistilledValueReturnedFromJS(kTitle, |
| 148 result->content[page_num], |
| 149 result->image_ids[page_num], |
| 150 next_page_url, |
| 151 prev_page_url); |
| 152 result->distilled_values.push_back(distilled_value.release()); |
| 153 } |
| 154 return result.Pass(); |
| 155 } |
| 156 |
| 157 void VerifyArticleProtoMatchesMultipageData( |
| 158 const dom_distiller::DistilledArticleProto* article_proto, |
| 159 const MultipageDistillerData* distiller_data, |
| 160 size_t pages_size) { |
| 161 EXPECT_EQ(pages_size, static_cast<size_t>(article_proto->pages_size())); |
| 162 EXPECT_EQ(kTitle, article_proto->title()); |
| 163 for (size_t page_num = 0; page_num < pages_size; ++page_num) { |
| 164 const dom_distiller::DistilledPageProto& page = |
| 165 article_proto->pages(page_num); |
| 166 EXPECT_EQ(distiller_data->content[page_num], page.html()); |
| 167 EXPECT_EQ(distiller_data->page_urls[page_num], page.url()); |
| 168 EXPECT_EQ(distiller_data->image_ids[page_num].size(), |
| 169 static_cast<size_t>(page.image_size())); |
| 170 const vector<int>& image_ids_for_page = distiller_data->image_ids[page_num]; |
| 171 for (size_t img_num = 0; img_num < image_ids_for_page.size(); ++img_num) { |
| 172 EXPECT_EQ(kImageData[image_ids_for_page[img_num]], |
| 173 page.image(img_num).data()); |
| 174 EXPECT_EQ(GetImageName(page_num + 1, img_num), |
| 175 page.image(img_num).name()); |
| 176 } |
| 177 } |
| 178 } |
60 | 179 |
61 } // namespace | 180 } // namespace |
62 | 181 |
63 namespace dom_distiller { | 182 namespace dom_distiller { |
64 | 183 |
65 class TestDistillerURLFetcher : public DistillerURLFetcher { | 184 class TestDistillerURLFetcher : public DistillerURLFetcher { |
66 public: | 185 public: |
67 TestDistillerURLFetcher() : DistillerURLFetcher(NULL) { | 186 TestDistillerURLFetcher() : DistillerURLFetcher(NULL) { |
68 responses_[kImageURLs[0]] = string(kImageData[0]); | 187 responses_[kImageURLs[0]] = string(kImageData[0]); |
69 responses_[kImageURLs[1]] = string(kImageData[1]); | 188 responses_[kImageURLs[1]] = string(kImageData[1]); |
70 } | 189 } |
71 | 190 |
72 void CallCallback(string url, const URLFetcherCallback& callback) { | 191 void CallCallback(string url, const URLFetcherCallback& callback) { |
73 callback.Run(responses_[url]); | 192 callback.Run(responses_[url]); |
74 } | 193 } |
75 | 194 |
76 virtual void FetchURL(const string& url, | 195 virtual void FetchURL(const string& url, |
77 const URLFetcherCallback& callback) OVERRIDE { | 196 const URLFetcherCallback& callback) OVERRIDE { |
78 ASSERT_TRUE(base::MessageLoop::current()); | 197 ASSERT_TRUE(base::MessageLoop::current()); |
79 base::MessageLoop::current()->PostTask( | 198 base::MessageLoop::current()->PostTask( |
80 FROM_HERE, | 199 FROM_HERE, |
81 base::Bind(&TestDistillerURLFetcher::CallCallback, | 200 base::Bind(&TestDistillerURLFetcher::CallCallback, |
82 base::Unretained(this), url, callback)); | 201 base::Unretained(this), |
| 202 url, |
| 203 callback)); |
83 } | 204 } |
84 | 205 |
85 std::map<string, string> responses_; | 206 std::map<string, string> responses_; |
86 }; | 207 }; |
87 | 208 |
88 | |
89 class TestDistillerURLFetcherFactory : public DistillerURLFetcherFactory { | 209 class TestDistillerURLFetcherFactory : public DistillerURLFetcherFactory { |
90 public: | 210 public: |
91 TestDistillerURLFetcherFactory() : DistillerURLFetcherFactory(NULL) {} | 211 TestDistillerURLFetcherFactory() : DistillerURLFetcherFactory(NULL) {} |
92 virtual ~TestDistillerURLFetcherFactory() {} | 212 virtual ~TestDistillerURLFetcherFactory() {} |
93 virtual DistillerURLFetcher* CreateDistillerURLFetcher() const OVERRIDE { | 213 virtual DistillerURLFetcher* CreateDistillerURLFetcher() const OVERRIDE { |
94 return new TestDistillerURLFetcher(); | 214 return new TestDistillerURLFetcher(); |
95 } | 215 } |
96 }; | 216 }; |
97 | 217 |
98 | |
99 class MockDistillerPage : public DistillerPage { | 218 class MockDistillerPage : public DistillerPage { |
100 public: | 219 public: |
101 MOCK_METHOD0(InitImpl, void()); | 220 MOCK_METHOD0(InitImpl, void()); |
102 MOCK_METHOD1(LoadURLImpl, void(const GURL& gurl)); | 221 MOCK_METHOD1(LoadURLImpl, void(const GURL& gurl)); |
103 MOCK_METHOD1(ExecuteJavaScriptImpl, void(const string& script)); | 222 MOCK_METHOD1(ExecuteJavaScriptImpl, void(const string& script)); |
104 | 223 |
105 explicit MockDistillerPage(DistillerPage::Delegate* delegate) | 224 explicit MockDistillerPage(DistillerPage::Delegate* delegate) |
106 : DistillerPage(delegate) {} | 225 : DistillerPage(delegate) {} |
107 }; | 226 }; |
108 | 227 |
109 | |
110 class MockDistillerPageFactory : public DistillerPageFactory { | 228 class MockDistillerPageFactory : public DistillerPageFactory { |
111 public: | 229 public: |
112 MOCK_CONST_METHOD1( | 230 MOCK_CONST_METHOD1( |
113 CreateDistillerPageMock, | 231 CreateDistillerPageMock, |
114 DistillerPage*(DistillerPage::Delegate* delegate)); | 232 DistillerPage*(DistillerPage::Delegate* delegate)); |
115 | 233 |
116 virtual scoped_ptr<DistillerPage> CreateDistillerPage( | 234 virtual scoped_ptr<DistillerPage> CreateDistillerPage( |
117 DistillerPage::Delegate* delegate) const OVERRIDE { | 235 DistillerPage::Delegate* delegate) const OVERRIDE { |
118 return scoped_ptr<DistillerPage>(CreateDistillerPageMock(delegate)); | 236 return scoped_ptr<DistillerPage>(CreateDistillerPageMock(delegate)); |
119 } | 237 } |
120 }; | 238 }; |
121 | 239 |
122 class DistillerTest : public testing::Test { | 240 class DistillerTest : public testing::Test { |
123 public: | 241 public: |
124 virtual ~DistillerTest() {} | 242 virtual ~DistillerTest() {} |
125 void OnDistillPageDone(scoped_ptr<DistilledArticleProto> proto) { | 243 void OnDistillArticleDone(scoped_ptr<DistilledArticleProto> proto) { |
126 article_proto_ = proto.Pass(); | 244 article_proto_ = proto.Pass(); |
127 } | 245 } |
128 | 246 |
| 247 void OnDistillArticleUpdate(const ArticleDistillationUpdate& article_update) { |
| 248 in_sequence_updates_.push_back(article_update); |
| 249 } |
| 250 |
| 251 void DistillPage(const std::string& url) { |
| 252 distiller_->DistillPage(GURL(url), |
| 253 base::Bind(&DistillerTest::OnDistillArticleDone, |
| 254 base::Unretained(this)), |
| 255 base::Bind(&DistillerTest::OnDistillArticleUpdate, |
| 256 base::Unretained(this))); |
| 257 } |
| 258 |
129 protected: | 259 protected: |
130 scoped_ptr<DistillerImpl> distiller_; | 260 scoped_ptr<DistillerImpl> distiller_; |
131 scoped_ptr<DistilledArticleProto> article_proto_; | 261 scoped_ptr<DistilledArticleProto> article_proto_; |
| 262 std::vector<ArticleDistillationUpdate> in_sequence_updates_; |
132 MockDistillerPageFactory page_factory_; | 263 MockDistillerPageFactory page_factory_; |
133 TestDistillerURLFetcherFactory url_fetcher_factory_; | 264 TestDistillerURLFetcherFactory url_fetcher_factory_; |
134 }; | 265 }; |
135 | 266 |
136 ACTION_P3(DistillerPageOnExecuteJavaScriptDone, distiller_page, url, list) { | 267 ACTION_P3(DistillerPageOnExecuteJavaScriptDone, distiller_page, url, list) { |
137 distiller_page->OnExecuteJavaScriptDone(url, list); | 268 distiller_page->OnExecuteJavaScriptDone(url, list); |
138 } | 269 } |
139 | 270 |
140 ACTION_P2(CreateMockDistillerPage, list, kurl) { | 271 ACTION_P2(CreateMockDistillerPage, list, kurl) { |
141 DistillerPage::Delegate* delegate = arg0; | 272 DistillerPage::Delegate* delegate = arg0; |
142 MockDistillerPage* distiller_page = new MockDistillerPage(delegate); | 273 MockDistillerPage* distiller_page = new MockDistillerPage(delegate); |
143 EXPECT_CALL(*distiller_page, InitImpl()); | 274 EXPECT_CALL(*distiller_page, InitImpl()); |
144 EXPECT_CALL(*distiller_page, LoadURLImpl(kurl)) | 275 EXPECT_CALL(*distiller_page, LoadURLImpl(kurl)) |
145 .WillOnce(testing::InvokeWithoutArgs(distiller_page, | 276 .WillOnce(testing::InvokeWithoutArgs(distiller_page, |
146 &DistillerPage::OnLoadURLDone)); | 277 &DistillerPage::OnLoadURLDone)); |
147 EXPECT_CALL(*distiller_page, ExecuteJavaScriptImpl(_)).WillOnce( | 278 EXPECT_CALL(*distiller_page, ExecuteJavaScriptImpl(_)).WillOnce( |
148 DistillerPageOnExecuteJavaScriptDone(distiller_page, kurl, list)); | 279 DistillerPageOnExecuteJavaScriptDone(distiller_page, kurl, list)); |
149 return distiller_page; | 280 return distiller_page; |
150 } | 281 } |
151 | 282 |
152 ACTION_P4(CreateMockDistillerPages, lists, kurls, num_pages, start_page_num) { | 283 ACTION_P3(CreateMockDistillerPages, |
| 284 distiller_data, |
| 285 pages_size, |
| 286 start_page_num) { |
153 DistillerPage::Delegate* delegate = arg0; | 287 DistillerPage::Delegate* delegate = arg0; |
154 MockDistillerPage* distiller_page = new MockDistillerPage(delegate); | 288 MockDistillerPage* distiller_page = new MockDistillerPage(delegate); |
155 EXPECT_CALL(*distiller_page, InitImpl()); | 289 EXPECT_CALL(*distiller_page, InitImpl()); |
156 { | 290 { |
157 testing::InSequence s; | 291 testing::InSequence s; |
158 // Distiller prefers distilling past pages first. E.g. when distillation | 292 vector<int> page_nums = GetPagesInSequence(start_page_num, pages_size); |
159 // starts on page 2 then pages are distilled in the order: 2, 1, 0, 3, 4. | 293 for (size_t page_num = 0; page_num < pages_size; ++page_num) { |
160 vector<int> page_nums; | |
161 for (int page = start_page_num; page >= 0; --page) | |
162 page_nums.push_back(page); | |
163 for (int page = start_page_num + 1; page < num_pages; ++page) | |
164 page_nums.push_back(page); | |
165 | |
166 for (size_t page_num = 0; page_num < page_nums.size(); ++page_num) { | |
167 int page = page_nums[page_num]; | 294 int page = page_nums[page_num]; |
168 GURL url = GURL(kurls[page]); | 295 GURL url = GURL(distiller_data->page_urls[page]); |
169 EXPECT_CALL(*distiller_page, LoadURLImpl(url)) | 296 EXPECT_CALL(*distiller_page, LoadURLImpl(url)) |
170 .WillOnce(testing::InvokeWithoutArgs(distiller_page, | 297 .WillOnce(testing::InvokeWithoutArgs(distiller_page, |
171 &DistillerPage::OnLoadURLDone)); | 298 &DistillerPage::OnLoadURLDone)); |
172 EXPECT_CALL(*distiller_page, ExecuteJavaScriptImpl(_)) | 299 EXPECT_CALL(*distiller_page, ExecuteJavaScriptImpl(_)) |
173 .WillOnce(DistillerPageOnExecuteJavaScriptDone( | 300 .WillOnce(DistillerPageOnExecuteJavaScriptDone( |
174 distiller_page, url, lists[page].get())); | 301 distiller_page, url, distiller_data->distilled_values[page])); |
175 } | 302 } |
176 } | 303 } |
177 return distiller_page; | 304 return distiller_page; |
178 } | 305 } |
179 | 306 |
180 TEST_F(DistillerTest, DistillPage) { | 307 TEST_F(DistillerTest, DistillPage) { |
181 base::MessageLoopForUI loop; | 308 base::MessageLoopForUI loop; |
182 scoped_ptr<base::ListValue> list = | 309 scoped_ptr<base::ListValue> list = |
183 CreateDistilledValueReturnedFromJS(kTitle, kContent, vector<int>(), ""); | 310 CreateDistilledValueReturnedFromJS(kTitle, kContent, vector<int>(), ""); |
184 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) | 311 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) |
185 .WillOnce(CreateMockDistillerPage(list.get(), GURL(kURL))); | 312 .WillOnce(CreateMockDistillerPage(list.get(), GURL(kURL))); |
186 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | 313 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
187 distiller_->Init(); | 314 distiller_->Init(); |
188 distiller_->DistillPage( | 315 DistillPage(kURL); |
189 GURL(kURL), | |
190 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | |
191 base::MessageLoop::current()->RunUntilIdle(); | 316 base::MessageLoop::current()->RunUntilIdle(); |
192 EXPECT_EQ(kTitle, article_proto_->title()); | 317 EXPECT_EQ(kTitle, article_proto_->title()); |
193 EXPECT_EQ(article_proto_->pages_size(), 1); | 318 EXPECT_EQ(article_proto_->pages_size(), 1); |
194 const DistilledPageProto& first_page = article_proto_->pages(0); | 319 const DistilledPageProto& first_page = article_proto_->pages(0); |
195 EXPECT_EQ(kContent, first_page.html()); | 320 EXPECT_EQ(kContent, first_page.html()); |
196 EXPECT_EQ(kURL, first_page.url()); | 321 EXPECT_EQ(kURL, first_page.url()); |
197 } | 322 } |
198 | 323 |
199 TEST_F(DistillerTest, DistillPageWithImages) { | 324 TEST_F(DistillerTest, DistillPageWithImages) { |
200 base::MessageLoopForUI loop; | 325 base::MessageLoopForUI loop; |
201 vector<int> image_indices; | 326 vector<int> image_indices; |
202 image_indices.push_back(0); | 327 image_indices.push_back(0); |
203 image_indices.push_back(1); | 328 image_indices.push_back(1); |
204 scoped_ptr<base::ListValue> list = | 329 scoped_ptr<base::ListValue> list = |
205 CreateDistilledValueReturnedFromJS(kTitle, kContent, image_indices, ""); | 330 CreateDistilledValueReturnedFromJS(kTitle, kContent, image_indices, ""); |
206 EXPECT_CALL(page_factory_, | 331 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) |
207 CreateDistillerPageMock(_)).WillOnce( | 332 .WillOnce(CreateMockDistillerPage(list.get(), GURL(kURL))); |
208 CreateMockDistillerPage(list.get(), GURL(kURL))); | |
209 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | 333 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
210 distiller_->Init(); | 334 distiller_->Init(); |
211 distiller_->DistillPage( | 335 DistillPage(kURL); |
212 GURL(kURL), | |
213 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | |
214 base::MessageLoop::current()->RunUntilIdle(); | 336 base::MessageLoop::current()->RunUntilIdle(); |
215 EXPECT_EQ(kTitle, article_proto_->title()); | 337 EXPECT_EQ(kTitle, article_proto_->title()); |
216 EXPECT_EQ(article_proto_->pages_size(), 1); | 338 EXPECT_EQ(article_proto_->pages_size(), 1); |
217 const DistilledPageProto& first_page = article_proto_->pages(0); | 339 const DistilledPageProto& first_page = article_proto_->pages(0); |
218 EXPECT_EQ(kContent, first_page.html()); | 340 EXPECT_EQ(kContent, first_page.html()); |
219 EXPECT_EQ(kURL, first_page.url()); | 341 EXPECT_EQ(kURL, first_page.url()); |
220 EXPECT_EQ(2, first_page.image_size()); | 342 EXPECT_EQ(2, first_page.image_size()); |
221 EXPECT_EQ(kImageData[0], first_page.image(0).data()); | 343 EXPECT_EQ(kImageData[0], first_page.image(0).data()); |
222 EXPECT_EQ(GetImageName(1, 0), first_page.image(0).name()); | 344 EXPECT_EQ(GetImageName(1, 0), first_page.image(0).name()); |
223 EXPECT_EQ(kImageData[1], first_page.image(1).data()); | 345 EXPECT_EQ(kImageData[1], first_page.image(1).data()); |
224 EXPECT_EQ(GetImageName(1, 1), first_page.image(1).name()); | 346 EXPECT_EQ(GetImageName(1, 1), first_page.image(1).name()); |
225 } | 347 } |
226 | 348 |
227 TEST_F(DistillerTest, DistillMultiplePages) { | 349 TEST_F(DistillerTest, DistillMultiplePages) { |
228 base::MessageLoopForUI loop; | 350 base::MessageLoopForUI loop; |
229 const int kNumPages = 8; | 351 const size_t kNumPages = 8; |
230 vector<int> image_indices[kNumPages]; | 352 scoped_ptr<MultipageDistillerData> distiller_data = |
231 string content[kNumPages]; | 353 CreateMultipageDistillerDataWithoutImages(kNumPages); |
232 string page_urls[kNumPages]; | |
233 scoped_ptr<base::ListValue> list[kNumPages]; | |
234 | 354 |
| 355 // Add images. |
235 int next_image_number = 0; | 356 int next_image_number = 0; |
236 | 357 for (size_t page_num = 0; page_num < kNumPages; ++page_num) { |
237 for (int page_num = 0; page_num < kNumPages; ++page_num) { | |
238 // Each page has different number of images. | 358 // Each page has different number of images. |
239 int tot_images = (page_num + kTotalImages) % (kTotalImages + 1); | 359 size_t tot_images = (page_num + kTotalImages) % (kTotalImages + 1); |
240 for (int img_num = 0; img_num < tot_images; img_num++) { | 360 vector<int> image_indices; |
241 image_indices[page_num].push_back(next_image_number); | 361 for (size_t img_num = 0; img_num < tot_images; img_num++) { |
| 362 image_indices.push_back(next_image_number); |
242 next_image_number = (next_image_number + 1) % kTotalImages; | 363 next_image_number = (next_image_number + 1) % kTotalImages; |
243 } | 364 } |
244 | 365 distiller_data->image_ids.push_back(image_indices); |
245 page_urls[page_num] = "http://a.com/" + base::IntToString(page_num); | |
246 content[page_num] = "Content for page:" + base::IntToString(page_num); | |
247 } | |
248 for (int i = 0; i < kNumPages; ++i) { | |
249 string next_page_url = ""; | |
250 if (i + 1 < kNumPages) | |
251 next_page_url = page_urls[i + 1]; | |
252 | |
253 list[i] = CreateDistilledValueReturnedFromJS( | |
254 kTitle, content[i], image_indices[i], next_page_url); | |
255 } | 366 } |
256 | 367 |
257 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) | 368 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) |
258 .WillOnce(CreateMockDistillerPages(list, page_urls, kNumPages, 0)); | 369 .WillOnce(CreateMockDistillerPages(distiller_data.get(), kNumPages, 0)); |
259 | 370 |
260 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | 371 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
261 distiller_->Init(); | 372 distiller_->Init(); |
262 distiller_->DistillPage( | 373 DistillPage(distiller_data->page_urls[0]); |
263 GURL(page_urls[0]), | |
264 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | |
265 base::MessageLoop::current()->RunUntilIdle(); | 374 base::MessageLoop::current()->RunUntilIdle(); |
266 EXPECT_EQ(kTitle, article_proto_->title()); | 375 VerifyArticleProtoMatchesMultipageData( |
267 EXPECT_EQ(article_proto_->pages_size(), kNumPages); | 376 article_proto_.get(), distiller_data.get(), kNumPages); |
268 for (int page_num = 0; page_num < kNumPages; ++page_num) { | |
269 const DistilledPageProto& page = article_proto_->pages(page_num); | |
270 EXPECT_EQ(content[page_num], page.html()); | |
271 EXPECT_EQ(page_urls[page_num], page.url()); | |
272 EXPECT_EQ(image_indices[page_num].size(), | |
273 static_cast<size_t>(page.image_size())); | |
274 for (size_t img_num = 0; img_num < image_indices[page_num].size(); | |
275 ++img_num) { | |
276 EXPECT_EQ(kImageData[image_indices[page_num][img_num]], | |
277 page.image(img_num).data()); | |
278 EXPECT_EQ(GetImageName(page_num + 1, img_num), | |
279 page.image(img_num).name()); | |
280 } | |
281 } | |
282 } | 377 } |
283 | 378 |
284 TEST_F(DistillerTest, DistillLinkLoop) { | 379 TEST_F(DistillerTest, DistillLinkLoop) { |
285 base::MessageLoopForUI loop; | 380 base::MessageLoopForUI loop; |
286 // Create a loop, the next page is same as the current page. This could | 381 // Create a loop, the next page is same as the current page. This could |
287 // happen if javascript misparses a next page link. | 382 // happen if javascript misparses a next page link. |
288 scoped_ptr<base::ListValue> list = | 383 scoped_ptr<base::ListValue> list = |
289 CreateDistilledValueReturnedFromJS(kTitle, kContent, vector<int>(), kURL); | 384 CreateDistilledValueReturnedFromJS(kTitle, kContent, vector<int>(), kURL); |
290 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) | 385 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) |
291 .WillOnce(CreateMockDistillerPage(list.get(), GURL(kURL))); | 386 .WillOnce(CreateMockDistillerPage(list.get(), GURL(kURL))); |
292 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | 387 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
293 distiller_->Init(); | 388 distiller_->Init(); |
294 distiller_->DistillPage( | 389 DistillPage(kURL); |
295 GURL(kURL), | |
296 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | |
297 base::MessageLoop::current()->RunUntilIdle(); | 390 base::MessageLoop::current()->RunUntilIdle(); |
298 EXPECT_EQ(kTitle, article_proto_->title()); | 391 EXPECT_EQ(kTitle, article_proto_->title()); |
299 EXPECT_EQ(article_proto_->pages_size(), 1); | 392 EXPECT_EQ(article_proto_->pages_size(), 1); |
300 } | 393 } |
301 | 394 |
302 TEST_F(DistillerTest, CheckMaxPageLimit) { | 395 TEST_F(DistillerTest, CheckMaxPageLimitExtraPage) { |
303 base::MessageLoopForUI loop; | 396 base::MessageLoopForUI loop; |
304 const size_t kMaxPagesInArticle = 10; | 397 const size_t kMaxPagesInArticle = 10; |
305 string page_urls[kMaxPagesInArticle]; | 398 scoped_ptr<MultipageDistillerData> distiller_data = |
306 scoped_ptr<base::ListValue> list[kMaxPagesInArticle]; | 399 CreateMultipageDistillerDataWithoutImages(kMaxPagesInArticle); |
307 | 400 |
308 // Note: Next page url of the last page of article is set. So distiller will | 401 // Note: Next page url of the last page of article is set. So distiller will |
309 // try to do kMaxPagesInArticle + 1 calls if the max article limit does not | 402 // try to do kMaxPagesInArticle + 1 calls if the max article limit does not |
310 // work. | 403 // work. |
311 string url_prefix = "http://a.com/"; | 404 scoped_ptr<base::ListValue> last_page_data = |
312 for (size_t page_num = 0; page_num < kMaxPagesInArticle; ++page_num) { | 405 CreateDistilledValueReturnedFromJS( |
313 page_urls[page_num] = url_prefix + base::IntToString(page_num + 1); | 406 kTitle, |
314 string content = "Content for page:" + base::IntToString(page_num); | 407 distiller_data->content[kMaxPagesInArticle - 1], |
315 string next_page_url = url_prefix + base::IntToString(page_num + 2); | 408 vector<int>(), |
316 list[page_num] = CreateDistilledValueReturnedFromJS( | 409 "", |
317 kTitle, content, vector<int>(), next_page_url); | 410 distiller_data->page_urls[kMaxPagesInArticle - 2]); |
318 } | |
319 | 411 |
320 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) | 412 distiller_data->distilled_values.pop_back(); |
321 .WillOnce(CreateMockDistillerPages( | 413 distiller_data->distilled_values.push_back(last_page_data.release()); |
322 list, page_urls, static_cast<int>(kMaxPagesInArticle), 0)); | |
323 | 414 |
| 415 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)).WillOnce( |
| 416 CreateMockDistillerPages(distiller_data.get(), kMaxPagesInArticle, 0)); |
324 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | 417 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
325 | 418 |
326 distiller_->SetMaxNumPagesInArticle(kMaxPagesInArticle); | 419 distiller_->SetMaxNumPagesInArticle(kMaxPagesInArticle); |
327 | 420 |
328 distiller_->Init(); | 421 distiller_->Init(); |
329 distiller_->DistillPage( | 422 DistillPage(distiller_data->page_urls[0]); |
330 GURL(page_urls[0]), | |
331 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | |
332 base::MessageLoop::current()->RunUntilIdle(); | 423 base::MessageLoop::current()->RunUntilIdle(); |
333 EXPECT_EQ(kTitle, article_proto_->title()); | 424 EXPECT_EQ(kTitle, article_proto_->title()); |
334 EXPECT_EQ(kMaxPagesInArticle, | 425 EXPECT_EQ(kMaxPagesInArticle, |
335 static_cast<size_t>(article_proto_->pages_size())); | 426 static_cast<size_t>(article_proto_->pages_size())); |
| 427 } |
336 | 428 |
337 // Now check if distilling an article with exactly the page limit works by | 429 TEST_F(DistillerTest, CheckMaxPageLimitExactLimit) { |
338 // resetting the next page url of the last page of the article. | 430 base::MessageLoopForUI loop; |
339 list[kMaxPagesInArticle - 1] = | 431 const size_t kMaxPagesInArticle = 10; |
340 CreateDistilledValueReturnedFromJS(kTitle, "Content", vector<int>(), ""); | 432 scoped_ptr<MultipageDistillerData> distiller_data = |
341 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) | 433 CreateMultipageDistillerDataWithoutImages(kMaxPagesInArticle); |
342 .WillOnce(CreateMockDistillerPages( | |
343 list, page_urls, static_cast<int>(kMaxPagesInArticle), 0)); | |
344 | 434 |
| 435 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)).WillOnce( |
| 436 CreateMockDistillerPages(distiller_data.get(), kMaxPagesInArticle, 0)); |
345 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | 437 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
| 438 |
| 439 // Check if distilling an article with exactly the page limit works. |
346 distiller_->SetMaxNumPagesInArticle(kMaxPagesInArticle); | 440 distiller_->SetMaxNumPagesInArticle(kMaxPagesInArticle); |
347 | 441 |
348 distiller_->Init(); | 442 distiller_->Init(); |
349 distiller_->DistillPage( | 443 |
350 GURL(page_urls[0]), | 444 DistillPage(distiller_data->page_urls[0]); |
351 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | |
352 base::MessageLoop::current()->RunUntilIdle(); | 445 base::MessageLoop::current()->RunUntilIdle(); |
353 EXPECT_EQ(kTitle, article_proto_->title()); | 446 EXPECT_EQ(kTitle, article_proto_->title()); |
354 EXPECT_EQ(kMaxPagesInArticle, | 447 EXPECT_EQ(kMaxPagesInArticle, |
355 static_cast<size_t>(article_proto_->pages_size())); | |
356 | |
357 // Now check if distilling an article with exactly the page limit works by | |
358 // resetting the next page url of the last page of the article. | |
359 list[kMaxPagesInArticle - 1] = | |
360 CreateDistilledValueReturnedFromJS(kTitle, "Content", vector<int>(), ""); | |
361 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) | |
362 .WillOnce(CreateMockDistillerPages( | |
363 list, page_urls, static_cast<int>(kMaxPagesInArticle), 0)); | |
364 | |
365 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | |
366 distiller_->SetMaxNumPagesInArticle(kMaxPagesInArticle); | |
367 | |
368 distiller_->Init(); | |
369 distiller_->DistillPage( | |
370 GURL(page_urls[0]), | |
371 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | |
372 base::MessageLoop::current()->RunUntilIdle(); | |
373 EXPECT_EQ(kTitle, article_proto_->title()); | |
374 EXPECT_EQ(kMaxPagesInArticle, | |
375 static_cast<size_t>(article_proto_->pages_size())); | 448 static_cast<size_t>(article_proto_->pages_size())); |
376 } | 449 } |
377 | 450 |
378 TEST_F(DistillerTest, SinglePageDistillationFailure) { | 451 TEST_F(DistillerTest, SinglePageDistillationFailure) { |
379 base::MessageLoopForUI loop; | 452 base::MessageLoopForUI loop; |
380 // To simulate failure return a null value. | 453 // To simulate failure return a null value. |
381 scoped_ptr<base::Value> nullValue(base::Value::CreateNullValue()); | 454 scoped_ptr<base::Value> nullValue(base::Value::CreateNullValue()); |
382 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) | 455 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) |
383 .WillOnce(CreateMockDistillerPage(nullValue.get(), GURL(kURL))); | 456 .WillOnce(CreateMockDistillerPage(nullValue.get(), GURL(kURL))); |
384 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | 457 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
385 distiller_->Init(); | 458 distiller_->Init(); |
386 distiller_->DistillPage( | 459 DistillPage(kURL); |
387 GURL(kURL), | |
388 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | |
389 base::MessageLoop::current()->RunUntilIdle(); | 460 base::MessageLoop::current()->RunUntilIdle(); |
390 EXPECT_EQ("", article_proto_->title()); | 461 EXPECT_EQ("", article_proto_->title()); |
391 EXPECT_EQ(0, article_proto_->pages_size()); | 462 EXPECT_EQ(0, article_proto_->pages_size()); |
392 } | 463 } |
393 | 464 |
394 TEST_F(DistillerTest, MultiplePagesDistillationFailure) { | 465 TEST_F(DistillerTest, MultiplePagesDistillationFailure) { |
395 base::MessageLoopForUI loop; | 466 base::MessageLoopForUI loop; |
396 const int kNumPages = 8; | 467 const size_t kNumPages = 8; |
397 string content[kNumPages]; | 468 scoped_ptr<MultipageDistillerData> distiller_data = |
398 string page_urls[kNumPages]; | 469 CreateMultipageDistillerDataWithoutImages(kNumPages); |
399 scoped_ptr<base::Value> distilled_values[kNumPages]; | 470 |
400 // The page number of the failed page. | 471 // The page number of the failed page. |
401 int failed_page_num = 3; | 472 size_t failed_page_num = 3; |
402 string url_prefix = "http://a.com/"; | 473 // reset distilled data of the failed page. |
403 for (int page_num = 0; page_num < kNumPages; ++page_num) { | 474 distiller_data->distilled_values.erase( |
404 page_urls[page_num] = url_prefix + base::IntToString(page_num); | 475 distiller_data->distilled_values.begin() + failed_page_num); |
405 content[page_num] = "Content for page:" + base::IntToString(page_num); | 476 distiller_data->distilled_values.insert( |
406 string next_page_url = url_prefix + base::IntToString(page_num + 1); | 477 distiller_data->distilled_values.begin() + failed_page_num, |
407 if (page_num != failed_page_num) { | 478 base::Value::CreateNullValue()); |
408 distilled_values[page_num] = CreateDistilledValueReturnedFromJS( | |
409 kTitle, content[page_num], vector<int>(), next_page_url); | |
410 } else { | |
411 distilled_values[page_num].reset(base::Value::CreateNullValue()); | |
412 } | |
413 } | |
414 | |
415 // Expect only calls till the failed page number. | 479 // Expect only calls till the failed page number. |
416 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) | 480 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)).WillOnce( |
417 .WillOnce(CreateMockDistillerPages( | 481 CreateMockDistillerPages(distiller_data.get(), failed_page_num + 1, 0)); |
418 distilled_values, page_urls, failed_page_num + 1, 0)); | |
419 | 482 |
420 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | 483 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
421 distiller_->Init(); | 484 distiller_->Init(); |
422 distiller_->DistillPage( | 485 DistillPage(distiller_data->page_urls[0]); |
423 GURL(page_urls[0]), | |
424 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | |
425 base::MessageLoop::current()->RunUntilIdle(); | 486 base::MessageLoop::current()->RunUntilIdle(); |
426 EXPECT_EQ(kTitle, article_proto_->title()); | 487 EXPECT_EQ(kTitle, article_proto_->title()); |
427 EXPECT_EQ(article_proto_->pages_size(), failed_page_num); | 488 VerifyArticleProtoMatchesMultipageData( |
428 for (int page_num = 0; page_num < failed_page_num; ++page_num) { | 489 article_proto_.get(), distiller_data.get(), failed_page_num); |
429 const DistilledPageProto& page = article_proto_->pages(page_num); | |
430 EXPECT_EQ(content[page_num], page.html()); | |
431 EXPECT_EQ(page_urls[page_num], page.url()); | |
432 } | |
433 } | 490 } |
434 | 491 |
435 TEST_F(DistillerTest, DistillPreviousPage) { | 492 TEST_F(DistillerTest, DistillPreviousPage) { |
436 base::MessageLoopForUI loop; | 493 base::MessageLoopForUI loop; |
437 const int kNumPages = 8; | 494 const size_t kNumPages = 8; |
438 string content[kNumPages]; | |
439 string page_urls[kNumPages]; | |
440 scoped_ptr<base::Value> distilled_values[kNumPages]; | |
441 | 495 |
442 // The page number of the article on which distillation starts. | 496 // The page number of the article on which distillation starts. |
443 int start_page_number = 3; | 497 int start_page_num = 3; |
444 string url_prefix = "http://a.com/"; | 498 scoped_ptr<MultipageDistillerData> distiller_data = |
445 for (int page_no = 0; page_no < kNumPages; ++page_no) { | 499 CreateMultipageDistillerDataWithoutImages(kNumPages); |
446 page_urls[page_no] = url_prefix + base::IntToString(page_no); | |
447 content[page_no] = "Content for page:" + base::IntToString(page_no); | |
448 string next_page_url = (page_no + 1 < kNumPages) | |
449 ? url_prefix + base::IntToString(page_no + 1) | |
450 : ""; | |
451 string prev_page_url = (page_no > 0) ? page_urls[page_no - 1] : ""; | |
452 distilled_values[page_no] = CreateDistilledValueReturnedFromJS( | |
453 kTitle, content[page_no], vector<int>(), next_page_url, prev_page_url); | |
454 } | |
455 | 500 |
456 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) | 501 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) |
457 .WillOnce(CreateMockDistillerPages( | 502 .WillOnce(CreateMockDistillerPages( |
458 distilled_values, page_urls, kNumPages, start_page_number)); | 503 distiller_data.get(), kNumPages, start_page_num)); |
459 | 504 |
460 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); | 505 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
461 distiller_->Init(); | 506 distiller_->Init(); |
462 distiller_->DistillPage( | 507 DistillPage(distiller_data->page_urls[start_page_num]); |
463 GURL(page_urls[start_page_number]), | 508 base::MessageLoop::current()->RunUntilIdle(); |
464 base::Bind(&DistillerTest::OnDistillPageDone, base::Unretained(this))); | 509 VerifyArticleProtoMatchesMultipageData( |
| 510 article_proto_.get(), distiller_data.get(), kNumPages); |
| 511 } |
| 512 |
| 513 TEST_F(DistillerTest, IncrementalUpdates) { |
| 514 base::MessageLoopForUI loop; |
| 515 const size_t kNumPages = 8; |
| 516 |
| 517 // The page number of the article on which distillation starts. |
| 518 int start_page_num = 3; |
| 519 scoped_ptr<MultipageDistillerData> distiller_data = |
| 520 CreateMultipageDistillerDataWithoutImages(kNumPages); |
| 521 |
| 522 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) |
| 523 .WillOnce(CreateMockDistillerPages( |
| 524 distiller_data.get(), kNumPages, start_page_num)); |
| 525 |
| 526 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
| 527 distiller_->Init(); |
| 528 DistillPage(distiller_data->page_urls[start_page_num]); |
465 base::MessageLoop::current()->RunUntilIdle(); | 529 base::MessageLoop::current()->RunUntilIdle(); |
466 EXPECT_EQ(kTitle, article_proto_->title()); | 530 EXPECT_EQ(kTitle, article_proto_->title()); |
467 EXPECT_EQ(kNumPages, article_proto_->pages_size()); | 531 EXPECT_EQ(kNumPages, static_cast<size_t>(article_proto_->pages_size())); |
468 for (int page_no = 0; page_no < kNumPages; ++page_no) { | 532 EXPECT_EQ(kNumPages, in_sequence_updates_.size()); |
469 const DistilledPageProto& page = article_proto_->pages(page_no); | 533 |
470 EXPECT_EQ(content[page_no], page.html()); | 534 VerifyIncrementalUpdatesMatch( |
471 EXPECT_EQ(page_urls[page_no], page.url()); | 535 distiller_data.get(), kNumPages, in_sequence_updates_, start_page_num); |
472 } | 536 } |
| 537 |
| 538 TEST_F(DistillerTest, IncrementalUpdatesDoNotDeleteFinalArticle) { |
| 539 base::MessageLoopForUI loop; |
| 540 const size_t kNumPages = 8; |
| 541 int start_page_num = 3; |
| 542 scoped_ptr<MultipageDistillerData> distiller_data = |
| 543 CreateMultipageDistillerDataWithoutImages(kNumPages); |
| 544 |
| 545 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) |
| 546 .WillOnce(CreateMockDistillerPages( |
| 547 distiller_data.get(), kNumPages, start_page_num)); |
| 548 |
| 549 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
| 550 distiller_->Init(); |
| 551 DistillPage(distiller_data->page_urls[start_page_num]); |
| 552 base::MessageLoop::current()->RunUntilIdle(); |
| 553 EXPECT_EQ(kNumPages, in_sequence_updates_.size()); |
| 554 |
| 555 in_sequence_updates_.clear(); |
| 556 |
| 557 // Should still be able to access article and pages. |
| 558 VerifyArticleProtoMatchesMultipageData( |
| 559 article_proto_.get(), distiller_data.get(), kNumPages); |
| 560 } |
| 561 |
| 562 TEST_F(DistillerTest, DeletingArticleDoesNotInterfereWithUpdates) { |
| 563 base::MessageLoopForUI loop; |
| 564 const size_t kNumPages = 8; |
| 565 scoped_ptr<MultipageDistillerData> distiller_data = |
| 566 CreateMultipageDistillerDataWithoutImages(kNumPages); |
| 567 // The page number of the article on which distillation starts. |
| 568 int start_page_num = 3; |
| 569 |
| 570 EXPECT_CALL(page_factory_, CreateDistillerPageMock(_)) |
| 571 .WillOnce(CreateMockDistillerPages( |
| 572 distiller_data.get(), kNumPages, start_page_num)); |
| 573 |
| 574 distiller_.reset(new DistillerImpl(page_factory_, url_fetcher_factory_)); |
| 575 distiller_->Init(); |
| 576 DistillPage(distiller_data->page_urls[start_page_num]); |
| 577 base::MessageLoop::current()->RunUntilIdle(); |
| 578 EXPECT_EQ(kNumPages, in_sequence_updates_.size()); |
| 579 EXPECT_EQ(kTitle, article_proto_->title()); |
| 580 EXPECT_EQ(kNumPages, static_cast<size_t>(article_proto_->pages_size())); |
| 581 |
| 582 // Delete the article. |
| 583 article_proto_.reset(); |
| 584 VerifyIncrementalUpdatesMatch( |
| 585 distiller_data.get(), kNumPages, in_sequence_updates_, start_page_num); |
473 } | 586 } |
474 | 587 |
475 } // namespace dom_distiller | 588 } // namespace dom_distiller |
OLD | NEW |