Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Side by Side Diff: components/dom_distiller/core/distiller_unittest.cc

Issue 178303004: Add incremental updates for multipage distillation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
OLDNEW
« no previous file with comments | « components/dom_distiller/core/distiller.cc ('k') | components/dom_distiller/core/dom_distiller_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698