Remove DistilledPageInfo and related structs.
[chromium-blink-merge.git] / components / dom_distiller / core / distiller_unittest.cc
blobe6e7797b58de6fc7b72d9ff00d72ad5c8023d0d2
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
3 // found in the LICENSE file.
5 #include <algorithm>
6 #include <map>
7 #include <string>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/location.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/path_service.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/values.h"
18 #include "components/dom_distiller/core/article_distillation_update.h"
19 #include "components/dom_distiller/core/distiller.h"
20 #include "components/dom_distiller/core/distiller_page.h"
21 #include "components/dom_distiller/core/fake_distiller_page.h"
22 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
23 #include "components/dom_distiller/core/proto/distilled_page.pb.h"
24 #include "net/url_request/url_request_context_getter.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "third_party/dom_distiller_js/dom_distiller.pb.h"
28 #include "third_party/dom_distiller_js/dom_distiller_json_converter.h"
29 #include "ui/base/resource/resource_bundle.h"
31 using std::vector;
32 using std::string;
33 using ::testing::Invoke;
34 using ::testing::Return;
35 using ::testing::_;
37 using dom_distiller::proto::DomDistillerOptions;
38 using dom_distiller::proto::DomDistillerResult;
40 namespace {
41 const char kTitle[] = "Title";
42 const char kContent[] = "Content";
43 const char kURL[] = "http://a.com/";
44 const size_t kTotalImages = 2;
45 const char* kImageURLs[kTotalImages] = {"http://a.com/img1.jpg",
46 "http://a.com/img2.jpg"};
47 const char* kImageData[kTotalImages] = {"abcde", "12345"};
49 const string GetImageName(int page_num, int image_num) {
50 return base::IntToString(page_num) + "_" + base::IntToString(image_num);
53 scoped_ptr<base::Value> CreateDistilledValueReturnedFromJS(
54 const string& title,
55 const string& content,
56 const vector<int>& image_indices,
57 const string& next_page_url,
58 const string& prev_page_url = "") {
59 DomDistillerResult result;
60 result.set_title(title);
61 result.mutable_distilled_content()->set_html(content);
62 result.mutable_pagination_info()->set_next_page(next_page_url);
63 result.mutable_pagination_info()->set_prev_page(prev_page_url);
65 for (size_t i = 0; i < image_indices.size(); ++i) {
66 result.add_image_urls(kImageURLs[image_indices[i]]);
69 return dom_distiller::proto::json::DomDistillerResult::WriteToValue(result);
72 // Return the sequence in which Distiller will distill pages.
73 // Note: ignores any delays due to fetching images etc.
74 vector<int> GetPagesInSequence(int start_page_num, int num_pages) {
75 // Distiller prefers distilling past pages first. E.g. when distillation
76 // starts on page 2 then pages are distilled in the order: 2, 1, 0, 3, 4.
77 vector<int> page_nums;
78 for (int page = start_page_num; page >= 0; --page)
79 page_nums.push_back(page);
80 for (int page = start_page_num + 1; page < num_pages; ++page)
81 page_nums.push_back(page);
82 return page_nums;
85 struct MultipageDistillerData {
86 public:
87 MultipageDistillerData() {}
88 ~MultipageDistillerData() {}
89 vector<string> page_urls;
90 vector<string> content;
91 vector<vector<int> > image_ids;
92 // The Javascript values returned by mock distiller.
93 ScopedVector<base::Value> distilled_values;
95 private:
96 DISALLOW_COPY_AND_ASSIGN(MultipageDistillerData);
99 void VerifyIncrementalUpdatesMatch(
100 const MultipageDistillerData* distiller_data,
101 int num_pages_in_article,
102 const vector<dom_distiller::ArticleDistillationUpdate>& incremental_updates,
103 int start_page_num) {
104 vector<int> page_seq =
105 GetPagesInSequence(start_page_num, num_pages_in_article);
106 // Updates should contain a list of pages. Pages in an update should be in
107 // the correct ascending page order regardless of |start_page_num|.
108 // E.g. if distillation starts at page 2 of a 3 page article, the updates
109 // will be [[2], [1, 2], [1, 2, 3]]. This example assumes that image fetches
110 // do not delay distillation of a page. There can be scenarios when image
111 // fetch delays distillation of a page (E.g. 1 is delayed due to image
112 // fetches so updates can be in this order [[2], [2,3], [1,2,3]].
113 for (size_t update_count = 0; update_count < incremental_updates.size();
114 ++update_count) {
115 const dom_distiller::ArticleDistillationUpdate& update =
116 incremental_updates[update_count];
117 EXPECT_EQ(update_count + 1, update.GetPagesSize());
119 vector<int> expected_page_nums_in_update(
120 page_seq.begin(), page_seq.begin() + update.GetPagesSize());
121 std::sort(expected_page_nums_in_update.begin(),
122 expected_page_nums_in_update.end());
124 // If we already got the first page then there is no previous page.
125 EXPECT_EQ((expected_page_nums_in_update[0] != 0), update.HasPrevPage());
127 // if we already got the last page then there is no next page.
128 EXPECT_EQ(
129 (*expected_page_nums_in_update.rbegin()) != num_pages_in_article - 1,
130 update.HasNextPage());
131 for (size_t j = 0; j < update.GetPagesSize(); ++j) {
132 int actual_page_num = expected_page_nums_in_update[j];
133 EXPECT_EQ(distiller_data->page_urls[actual_page_num],
134 update.GetDistilledPage(j).url());
135 EXPECT_EQ(distiller_data->content[actual_page_num],
136 update.GetDistilledPage(j).html());
141 scoped_ptr<MultipageDistillerData> CreateMultipageDistillerDataWithoutImages(
142 size_t pages_size) {
143 scoped_ptr<MultipageDistillerData> result(new MultipageDistillerData());
144 string url_prefix = "http://a.com/";
145 for (size_t page_num = 0; page_num < pages_size; ++page_num) {
146 result->page_urls.push_back(url_prefix + base::IntToString(page_num));
147 result->content.push_back("Content for page:" +
148 base::IntToString(page_num));
149 result->image_ids.push_back(vector<int>());
150 string next_page_url = (page_num + 1 < pages_size)
151 ? url_prefix + base::IntToString(page_num + 1)
152 : "";
153 string prev_page_url =
154 (page_num > 0) ? result->page_urls[page_num - 1] : "";
155 scoped_ptr<base::Value> distilled_value =
156 CreateDistilledValueReturnedFromJS(kTitle,
157 result->content[page_num],
158 result->image_ids[page_num],
159 next_page_url,
160 prev_page_url);
161 result->distilled_values.push_back(distilled_value.release());
163 return result.Pass();
166 void VerifyArticleProtoMatchesMultipageData(
167 const dom_distiller::DistilledArticleProto* article_proto,
168 const MultipageDistillerData* distiller_data,
169 size_t pages_size) {
170 ASSERT_EQ(pages_size, static_cast<size_t>(article_proto->pages_size()));
171 EXPECT_EQ(kTitle, article_proto->title());
172 for (size_t page_num = 0; page_num < pages_size; ++page_num) {
173 const dom_distiller::DistilledPageProto& page =
174 article_proto->pages(page_num);
175 EXPECT_EQ(distiller_data->content[page_num], page.html());
176 EXPECT_EQ(distiller_data->page_urls[page_num], page.url());
177 EXPECT_EQ(distiller_data->image_ids[page_num].size(),
178 static_cast<size_t>(page.image_size()));
179 const vector<int>& image_ids_for_page = distiller_data->image_ids[page_num];
180 for (size_t img_num = 0; img_num < image_ids_for_page.size(); ++img_num) {
181 EXPECT_EQ(kImageData[image_ids_for_page[img_num]],
182 page.image(img_num).data());
183 EXPECT_EQ(GetImageName(page_num + 1, img_num),
184 page.image(img_num).name());
189 void AddComponentsResources() {
190 base::FilePath pak_file;
191 base::FilePath pak_dir;
192 PathService::Get(base::DIR_MODULE, &pak_dir);
193 pak_file = pak_dir.Append(FILE_PATH_LITERAL("components_resources.pak"));
194 ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
195 pak_file, ui::SCALE_FACTOR_NONE);
198 } // namespace
200 namespace dom_distiller {
202 using test::MockDistillerPage;
203 using test::MockDistillerPageFactory;
205 class TestDistillerURLFetcher : public DistillerURLFetcher {
206 public:
207 explicit TestDistillerURLFetcher(bool delay_fetch)
208 : DistillerURLFetcher(NULL), delay_fetch_(delay_fetch) {
209 responses_[kImageURLs[0]] = string(kImageData[0]);
210 responses_[kImageURLs[1]] = string(kImageData[1]);
213 virtual void FetchURL(const string& url,
214 const URLFetcherCallback& callback) OVERRIDE {
215 ASSERT_FALSE(callback.is_null());
216 url_ = url;
217 callback_ = callback;
218 if (!delay_fetch_) {
219 PostCallbackTask();
223 void PostCallbackTask() {
224 ASSERT_TRUE(base::MessageLoop::current());
225 ASSERT_FALSE(callback_.is_null());
226 base::MessageLoop::current()->PostTask(
227 FROM_HERE, base::Bind(callback_, responses_[url_]));
230 private:
231 std::map<string, string> responses_;
232 string url_;
233 URLFetcherCallback callback_;
234 bool delay_fetch_;
237 class TestDistillerURLFetcherFactory : public DistillerURLFetcherFactory {
238 public:
239 TestDistillerURLFetcherFactory() : DistillerURLFetcherFactory(NULL) {}
241 virtual ~TestDistillerURLFetcherFactory() {}
242 virtual DistillerURLFetcher* CreateDistillerURLFetcher() const OVERRIDE {
243 return new TestDistillerURLFetcher(false);
247 class MockDistillerURLFetcherFactory : public DistillerURLFetcherFactory {
248 public:
249 MockDistillerURLFetcherFactory() : DistillerURLFetcherFactory(NULL) {}
250 virtual ~MockDistillerURLFetcherFactory() {}
252 MOCK_CONST_METHOD0(CreateDistillerURLFetcher, DistillerURLFetcher*());
255 class DistillerTest : public testing::Test {
256 public:
257 virtual ~DistillerTest() {}
259 virtual void SetUp() OVERRIDE {
260 AddComponentsResources();
263 void OnDistillArticleDone(scoped_ptr<DistilledArticleProto> proto) {
264 article_proto_ = proto.Pass();
267 void OnDistillArticleUpdate(const ArticleDistillationUpdate& article_update) {
268 in_sequence_updates_.push_back(article_update);
271 void DistillPage(const std::string& url,
272 scoped_ptr<DistillerPage> distiller_page) {
273 distiller_->DistillPage(GURL(url),
274 distiller_page.Pass(),
275 base::Bind(&DistillerTest::OnDistillArticleDone,
276 base::Unretained(this)),
277 base::Bind(&DistillerTest::OnDistillArticleUpdate,
278 base::Unretained(this)));
281 protected:
282 scoped_ptr<DistillerImpl> distiller_;
283 scoped_ptr<DistilledArticleProto> article_proto_;
284 std::vector<ArticleDistillationUpdate> in_sequence_updates_;
285 MockDistillerPageFactory page_factory_;
286 TestDistillerURLFetcherFactory url_fetcher_factory_;
289 ACTION_P3(DistillerPageOnDistillationDone, distiller_page, url, result) {
290 distiller_page->OnDistillationDone(url, result);
293 scoped_ptr<DistillerPage> CreateMockDistillerPage(const base::Value* result,
294 const GURL& url) {
295 MockDistillerPage* distiller_page = new MockDistillerPage();
296 EXPECT_CALL(*distiller_page, DistillPageImpl(url, _))
297 .WillOnce(DistillerPageOnDistillationDone(distiller_page, url, result));
298 return scoped_ptr<DistillerPage>(distiller_page).Pass();
301 scoped_ptr<DistillerPage> CreateMockDistillerPageWithPendingJSCallback(
302 MockDistillerPage** distiller_page_ptr,
303 const GURL& url) {
304 MockDistillerPage* distiller_page = new MockDistillerPage();
305 *distiller_page_ptr = distiller_page;
306 EXPECT_CALL(*distiller_page, DistillPageImpl(url, _));
307 return scoped_ptr<DistillerPage>(distiller_page).Pass();
310 scoped_ptr<DistillerPage> CreateMockDistillerPages(
311 MultipageDistillerData* distiller_data,
312 size_t pages_size,
313 int start_page_num) {
314 MockDistillerPage* distiller_page = new MockDistillerPage();
316 testing::InSequence s;
317 vector<int> page_nums = GetPagesInSequence(start_page_num, pages_size);
318 for (size_t page_num = 0; page_num < pages_size; ++page_num) {
319 int page = page_nums[page_num];
320 GURL url = GURL(distiller_data->page_urls[page]);
321 EXPECT_CALL(*distiller_page, DistillPageImpl(url, _))
322 .WillOnce(DistillerPageOnDistillationDone(
323 distiller_page, url, distiller_data->distilled_values[page]));
326 return scoped_ptr<DistillerPage>(distiller_page).Pass();
329 TEST_F(DistillerTest, DistillPage) {
330 base::MessageLoopForUI loop;
331 scoped_ptr<base::Value> result =
332 CreateDistilledValueReturnedFromJS(kTitle, kContent, vector<int>(), "");
333 distiller_.reset(
334 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
335 DistillPage(kURL, CreateMockDistillerPage(result.get(), GURL(kURL)).Pass());
336 base::MessageLoop::current()->RunUntilIdle();
337 EXPECT_EQ(kTitle, article_proto_->title());
338 ASSERT_EQ(article_proto_->pages_size(), 1);
339 const DistilledPageProto& first_page = article_proto_->pages(0);
340 EXPECT_EQ(kContent, first_page.html());
341 EXPECT_EQ(kURL, first_page.url());
344 TEST_F(DistillerTest, DistillPageWithImages) {
345 base::MessageLoopForUI loop;
346 vector<int> image_indices;
347 image_indices.push_back(0);
348 image_indices.push_back(1);
349 scoped_ptr<base::Value> result =
350 CreateDistilledValueReturnedFromJS(kTitle, kContent, image_indices, "");
351 distiller_.reset(
352 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
353 DistillPage(kURL, CreateMockDistillerPage(result.get(), GURL(kURL)).Pass());
354 base::MessageLoop::current()->RunUntilIdle();
355 EXPECT_EQ(kTitle, article_proto_->title());
356 ASSERT_EQ(article_proto_->pages_size(), 1);
357 const DistilledPageProto& first_page = article_proto_->pages(0);
358 EXPECT_EQ(kContent, first_page.html());
359 EXPECT_EQ(kURL, first_page.url());
360 ASSERT_EQ(2, first_page.image_size());
361 EXPECT_EQ(kImageData[0], first_page.image(0).data());
362 EXPECT_EQ(GetImageName(1, 0), first_page.image(0).name());
363 EXPECT_EQ(kImageData[1], first_page.image(1).data());
364 EXPECT_EQ(GetImageName(1, 1), first_page.image(1).name());
367 TEST_F(DistillerTest, DistillMultiplePages) {
368 base::MessageLoopForUI loop;
369 const size_t kNumPages = 8;
370 scoped_ptr<MultipageDistillerData> distiller_data =
371 CreateMultipageDistillerDataWithoutImages(kNumPages);
373 // Add images.
374 int next_image_number = 0;
375 for (size_t page_num = 0; page_num < kNumPages; ++page_num) {
376 // Each page has different number of images.
377 size_t tot_images = (page_num + kTotalImages) % (kTotalImages + 1);
378 vector<int> image_indices;
379 for (size_t img_num = 0; img_num < tot_images; img_num++) {
380 image_indices.push_back(next_image_number);
381 next_image_number = (next_image_number + 1) % kTotalImages;
383 distiller_data->image_ids.push_back(image_indices);
386 distiller_.reset(
387 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
388 DistillPage(
389 distiller_data->page_urls[0],
390 CreateMockDistillerPages(distiller_data.get(), kNumPages, 0).Pass());
391 base::MessageLoop::current()->RunUntilIdle();
392 VerifyArticleProtoMatchesMultipageData(
393 article_proto_.get(), distiller_data.get(), kNumPages);
396 TEST_F(DistillerTest, DistillLinkLoop) {
397 base::MessageLoopForUI loop;
398 // Create a loop, the next page is same as the current page. This could
399 // happen if javascript misparses a next page link.
400 scoped_ptr<base::Value> result =
401 CreateDistilledValueReturnedFromJS(kTitle, kContent, vector<int>(), kURL);
402 distiller_.reset(
403 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
404 DistillPage(kURL, CreateMockDistillerPage(result.get(), GURL(kURL)).Pass());
405 base::MessageLoop::current()->RunUntilIdle();
406 EXPECT_EQ(kTitle, article_proto_->title());
407 EXPECT_EQ(article_proto_->pages_size(), 1);
410 TEST_F(DistillerTest, CheckMaxPageLimitExtraPage) {
411 base::MessageLoopForUI loop;
412 const size_t kMaxPagesInArticle = 10;
413 scoped_ptr<MultipageDistillerData> distiller_data =
414 CreateMultipageDistillerDataWithoutImages(kMaxPagesInArticle);
416 // Note: Next page url of the last page of article is set. So distiller will
417 // try to do kMaxPagesInArticle + 1 calls if the max article limit does not
418 // work.
419 scoped_ptr<base::Value> last_page_data =
420 CreateDistilledValueReturnedFromJS(
421 kTitle,
422 distiller_data->content[kMaxPagesInArticle - 1],
423 vector<int>(),
425 distiller_data->page_urls[kMaxPagesInArticle - 2]);
427 distiller_data->distilled_values.pop_back();
428 distiller_data->distilled_values.push_back(last_page_data.release());
430 distiller_.reset(
431 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
433 distiller_->SetMaxNumPagesInArticle(kMaxPagesInArticle);
435 DistillPage(distiller_data->page_urls[0],
436 CreateMockDistillerPages(
437 distiller_data.get(), kMaxPagesInArticle, 0).Pass());
438 base::MessageLoop::current()->RunUntilIdle();
439 EXPECT_EQ(kTitle, article_proto_->title());
440 EXPECT_EQ(kMaxPagesInArticle,
441 static_cast<size_t>(article_proto_->pages_size()));
444 TEST_F(DistillerTest, CheckMaxPageLimitExactLimit) {
445 base::MessageLoopForUI loop;
446 const size_t kMaxPagesInArticle = 10;
447 scoped_ptr<MultipageDistillerData> distiller_data =
448 CreateMultipageDistillerDataWithoutImages(kMaxPagesInArticle);
450 distiller_.reset(
451 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
453 // Check if distilling an article with exactly the page limit works.
454 distiller_->SetMaxNumPagesInArticle(kMaxPagesInArticle);
456 DistillPage(distiller_data->page_urls[0],
457 CreateMockDistillerPages(
458 distiller_data.get(), kMaxPagesInArticle, 0).Pass());
459 base::MessageLoop::current()->RunUntilIdle();
460 EXPECT_EQ(kTitle, article_proto_->title());
461 EXPECT_EQ(kMaxPagesInArticle,
462 static_cast<size_t>(article_proto_->pages_size()));
465 TEST_F(DistillerTest, SinglePageDistillationFailure) {
466 base::MessageLoopForUI loop;
467 // To simulate failure return a null value.
468 scoped_ptr<base::Value> nullValue(base::Value::CreateNullValue());
469 distiller_.reset(
470 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
471 DistillPage(kURL,
472 CreateMockDistillerPage(nullValue.get(), GURL(kURL)).Pass());
473 base::MessageLoop::current()->RunUntilIdle();
474 EXPECT_EQ("", article_proto_->title());
475 EXPECT_EQ(0, article_proto_->pages_size());
478 TEST_F(DistillerTest, MultiplePagesDistillationFailure) {
479 base::MessageLoopForUI loop;
480 const size_t kNumPages = 8;
481 scoped_ptr<MultipageDistillerData> distiller_data =
482 CreateMultipageDistillerDataWithoutImages(kNumPages);
484 // The page number of the failed page.
485 size_t failed_page_num = 3;
486 // reset distilled data of the failed page.
487 distiller_data->distilled_values.erase(
488 distiller_data->distilled_values.begin() + failed_page_num);
489 distiller_data->distilled_values.insert(
490 distiller_data->distilled_values.begin() + failed_page_num,
491 base::Value::CreateNullValue());
492 // Expect only calls till the failed page number.
493 distiller_.reset(
494 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
495 DistillPage(distiller_data->page_urls[0],
496 CreateMockDistillerPages(
497 distiller_data.get(), failed_page_num + 1, 0).Pass());
498 base::MessageLoop::current()->RunUntilIdle();
499 EXPECT_EQ(kTitle, article_proto_->title());
500 VerifyArticleProtoMatchesMultipageData(
501 article_proto_.get(), distiller_data.get(), failed_page_num);
504 TEST_F(DistillerTest, DistillPreviousPage) {
505 base::MessageLoopForUI loop;
506 const size_t kNumPages = 8;
508 // The page number of the article on which distillation starts.
509 int start_page_num = 3;
510 scoped_ptr<MultipageDistillerData> distiller_data =
511 CreateMultipageDistillerDataWithoutImages(kNumPages);
513 distiller_.reset(
514 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
515 DistillPage(distiller_data->page_urls[start_page_num],
516 CreateMockDistillerPages(
517 distiller_data.get(), kNumPages, start_page_num).Pass());
518 base::MessageLoop::current()->RunUntilIdle();
519 VerifyArticleProtoMatchesMultipageData(
520 article_proto_.get(), distiller_data.get(), kNumPages);
523 TEST_F(DistillerTest, IncrementalUpdates) {
524 base::MessageLoopForUI loop;
525 const size_t kNumPages = 8;
527 // The page number of the article on which distillation starts.
528 int start_page_num = 3;
529 scoped_ptr<MultipageDistillerData> distiller_data =
530 CreateMultipageDistillerDataWithoutImages(kNumPages);
532 distiller_.reset(
533 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
534 DistillPage(distiller_data->page_urls[start_page_num],
535 CreateMockDistillerPages(
536 distiller_data.get(), kNumPages, start_page_num).Pass());
537 base::MessageLoop::current()->RunUntilIdle();
538 EXPECT_EQ(kTitle, article_proto_->title());
539 ASSERT_EQ(kNumPages, static_cast<size_t>(article_proto_->pages_size()));
540 EXPECT_EQ(kNumPages, in_sequence_updates_.size());
542 VerifyIncrementalUpdatesMatch(
543 distiller_data.get(), kNumPages, in_sequence_updates_, start_page_num);
546 TEST_F(DistillerTest, IncrementalUpdatesDoNotDeleteFinalArticle) {
547 base::MessageLoopForUI loop;
548 const size_t kNumPages = 8;
549 int start_page_num = 3;
550 scoped_ptr<MultipageDistillerData> distiller_data =
551 CreateMultipageDistillerDataWithoutImages(kNumPages);
553 distiller_.reset(
554 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
555 DistillPage(distiller_data->page_urls[start_page_num],
556 CreateMockDistillerPages(
557 distiller_data.get(), kNumPages, start_page_num).Pass());
558 base::MessageLoop::current()->RunUntilIdle();
559 EXPECT_EQ(kNumPages, in_sequence_updates_.size());
561 in_sequence_updates_.clear();
563 // Should still be able to access article and pages.
564 VerifyArticleProtoMatchesMultipageData(
565 article_proto_.get(), distiller_data.get(), kNumPages);
568 TEST_F(DistillerTest, DeletingArticleDoesNotInterfereWithUpdates) {
569 base::MessageLoopForUI loop;
570 const size_t kNumPages = 8;
571 scoped_ptr<MultipageDistillerData> distiller_data =
572 CreateMultipageDistillerDataWithoutImages(kNumPages);
573 // The page number of the article on which distillation starts.
574 int start_page_num = 3;
576 distiller_.reset(
577 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
578 DistillPage(distiller_data->page_urls[start_page_num],
579 CreateMockDistillerPages(
580 distiller_data.get(), kNumPages, start_page_num).Pass());
581 base::MessageLoop::current()->RunUntilIdle();
582 EXPECT_EQ(kNumPages, in_sequence_updates_.size());
583 EXPECT_EQ(kTitle, article_proto_->title());
584 ASSERT_EQ(kNumPages, static_cast<size_t>(article_proto_->pages_size()));
586 // Delete the article.
587 article_proto_.reset();
588 VerifyIncrementalUpdatesMatch(
589 distiller_data.get(), kNumPages, in_sequence_updates_, start_page_num);
592 TEST_F(DistillerTest, CancelWithDelayedImageFetchCallback) {
593 base::MessageLoopForUI loop;
594 vector<int> image_indices;
595 image_indices.push_back(0);
596 scoped_ptr<base::Value> distilled_value =
597 CreateDistilledValueReturnedFromJS(kTitle, kContent, image_indices, "");
598 TestDistillerURLFetcher* delayed_fetcher = new TestDistillerURLFetcher(true);
599 MockDistillerURLFetcherFactory mock_url_fetcher_factory;
600 EXPECT_CALL(mock_url_fetcher_factory, CreateDistillerURLFetcher())
601 .WillOnce(Return(delayed_fetcher));
602 distiller_.reset(
603 new DistillerImpl(mock_url_fetcher_factory, DomDistillerOptions()));
604 DistillPage(
605 kURL, CreateMockDistillerPage(distilled_value.get(), GURL(kURL)).Pass());
606 base::MessageLoop::current()->RunUntilIdle();
608 // Post callback from the url fetcher and then delete the distiller.
609 delayed_fetcher->PostCallbackTask();
610 distiller_.reset();
612 base::MessageLoop::current()->RunUntilIdle();
615 TEST_F(DistillerTest, CancelWithDelayedJSCallback) {
616 base::MessageLoopForUI loop;
617 scoped_ptr<base::Value> distilled_value =
618 CreateDistilledValueReturnedFromJS(kTitle, kContent, vector<int>(), "");
619 MockDistillerPage* distiller_page = NULL;
620 distiller_.reset(
621 new DistillerImpl(url_fetcher_factory_, DomDistillerOptions()));
622 DistillPage(kURL,
623 CreateMockDistillerPageWithPendingJSCallback(&distiller_page,
624 GURL(kURL)));
625 base::MessageLoop::current()->RunUntilIdle();
627 ASSERT_TRUE(distiller_page);
628 // Post the task to execute javascript and then delete the distiller.
629 distiller_page->OnDistillationDone(GURL(kURL), distilled_value.get());
630 distiller_.reset();
632 base::MessageLoop::current()->RunUntilIdle();
635 } // namespace dom_distiller