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

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

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

Powered by Google App Engine
This is Rietveld 408576698