| 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 |