Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "components/ntp_snippets/remote/ntp_snippets_fetcher.h" | 5 #include "components/ntp_snippets/remote/ntp_snippets_fetcher.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 53 const char kAPIKey[] = "fakeAPIkey"; | 53 const char kAPIKey[] = "fakeAPIkey"; |
| 54 const char kTestChromeReaderUrl[] = | 54 const char kTestChromeReaderUrl[] = |
| 55 "https://chromereader-pa.googleapis.com/v1/fetch?key=fakeAPIkey"; | 55 "https://chromereader-pa.googleapis.com/v1/fetch?key=fakeAPIkey"; |
| 56 const char kTestChromeContentSuggestionsUrl[] = | 56 const char kTestChromeContentSuggestionsUrl[] = |
| 57 "https://chromecontentsuggestions-pa.googleapis.com/v1/suggestions/" | 57 "https://chromecontentsuggestions-pa.googleapis.com/v1/suggestions/" |
| 58 "fetch?key=fakeAPIkey"; | 58 "fetch?key=fakeAPIkey"; |
| 59 | 59 |
| 60 // Artificial time delay for JSON parsing. | 60 // Artificial time delay for JSON parsing. |
| 61 const int64_t kTestJsonParsingLatencyMs = 20; | 61 const int64_t kTestJsonParsingLatencyMs = 20; |
| 62 | 62 |
| 63 ACTION_P(MoveArgumentPointeeTo, ptr) { | 63 ACTION_P(MoveArgument1PointeeTo, ptr) { |
| 64 *ptr = std::move(*arg0); | 64 *ptr = std::move(*arg1); |
| 65 } | 65 } |
| 66 | 66 |
| 67 MATCHER(HasValue, "") { | 67 MATCHER(HasValue, "") { |
| 68 return static_cast<bool>(*arg); | 68 return static_cast<bool>(*arg); |
| 69 } | 69 } |
| 70 | 70 |
| 71 MATCHER(IsEmptyArticleList, "is an empty list of articles") { | 71 MATCHER(IsEmptyArticleList, "is an empty list of articles") { |
| 72 NTPSnippetsFetcher::OptionalFetchedCategories& fetched_categories = *arg; | 72 NTPSnippetsFetcher::OptionalFetchedCategories& fetched_categories = *arg; |
| 73 return fetched_categories && fetched_categories->size() == 1 && | 73 return fetched_categories && fetched_categories->size() == 1 && |
| 74 fetched_categories->begin()->snippets.empty(); | 74 fetched_categories->begin()->snippets.empty(); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 142 << "parse error: " << err_msg; | 142 << "parse error: " << err_msg; |
| 143 return false; | 143 return false; |
| 144 } | 144 } |
| 145 return base::Value::Equals(actual.get(), expected.get()); | 145 return base::Value::Equals(actual.get(), expected.get()); |
| 146 } | 146 } |
| 147 | 147 |
| 148 class MockSnippetsAvailableCallback { | 148 class MockSnippetsAvailableCallback { |
| 149 public: | 149 public: |
| 150 // Workaround for gMock's lack of support for movable arguments. | 150 // Workaround for gMock's lack of support for movable arguments. |
| 151 void WrappedRun( | 151 void WrappedRun( |
| 152 NTPSnippetsFetcher::FetchResult fetch_result, | |
| 152 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { | 153 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { |
| 153 Run(&fetched_categories); | 154 Run(fetch_result, &fetched_categories); |
| 154 } | 155 } |
| 155 | 156 |
| 156 MOCK_METHOD1( | 157 MOCK_METHOD2( |
| 157 Run, | 158 Run, |
| 158 void(NTPSnippetsFetcher::OptionalFetchedCategories* fetched_categories)); | 159 void(NTPSnippetsFetcher::FetchResult fetch_result, |
| 160 NTPSnippetsFetcher::OptionalFetchedCategories* fetched_categories)); | |
| 159 }; | 161 }; |
| 160 | 162 |
| 161 // Factory for FakeURLFetcher objects that always generate errors. | 163 // Factory for FakeURLFetcher objects that always generate errors. |
| 162 class FailingFakeURLFetcherFactory : public net::URLFetcherFactory { | 164 class FailingFakeURLFetcherFactory : public net::URLFetcherFactory { |
| 163 public: | 165 public: |
| 164 std::unique_ptr<net::URLFetcher> CreateURLFetcher( | 166 std::unique_ptr<net::URLFetcher> CreateURLFetcher( |
| 165 int id, const GURL& url, net::URLFetcher::RequestType request_type, | 167 int id, const GURL& url, net::URLFetcher::RequestType request_type, |
| 166 net::URLFetcherDelegate* d) override { | 168 net::URLFetcherDelegate* d) override { |
| 167 return base::MakeUnique<net::FakeURLFetcher>( | 169 return base::MakeUnique<net::FakeURLFetcher>( |
| 168 url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND, | 170 url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND, |
| (...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 603 " \"url\" : \"http://localhost/foobar\"," | 605 " \"url\" : \"http://localhost/foobar\"," |
| 604 " \"sourceCorpusInfo\" : [{" | 606 " \"sourceCorpusInfo\" : [{" |
| 605 " \"ampUrl\" : \"http://localhost/amp\"," | 607 " \"ampUrl\" : \"http://localhost/amp\"," |
| 606 " \"corpusId\" : \"http://localhost/foobar\"," | 608 " \"corpusId\" : \"http://localhost/foobar\"," |
| 607 " \"publisherData\": { \"sourceName\" : \"Foo News\" }" | 609 " \"publisherData\": { \"sourceName\" : \"Foo News\" }" |
| 608 " }]" | 610 " }]" |
| 609 " }" | 611 " }" |
| 610 "}]}"; | 612 "}]}"; |
| 611 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, | 613 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, |
| 612 net::URLRequestStatus::SUCCESS); | 614 net::URLRequestStatus::SUCCESS); |
| 613 EXPECT_CALL( | 615 EXPECT_CALL(mock_callback(), |
| 614 mock_callback(), | 616 Run(NTPSnippetsFetcher::FetchResult::SUCCESS, |
| 615 Run(AllOf(IsSingleArticle("http://localhost/foobar"), | 617 AllOf(IsSingleArticle("http://localhost/foobar"), |
| 616 FirstCategoryHasInfo(IsCategoryInfoForArticles())))); | 618 FirstCategoryHasInfo(IsCategoryInfoForArticles())))); |
| 617 snippets_fetcher().FetchSnippets( | 619 snippets_fetcher().FetchSnippets( |
| 618 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 620 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 619 FastForwardUntilNoTasksRemain(); | 621 FastForwardUntilNoTasksRemain(); |
| 620 EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK")); | 622 EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK")); |
| 621 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); | 623 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); |
| 622 EXPECT_THAT(histogram_tester().GetAllSamples( | 624 EXPECT_THAT(histogram_tester().GetAllSamples( |
| 623 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), | 625 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), |
| 624 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); | 626 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); |
| 625 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), | 627 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), |
| 626 ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs, | 628 ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs, |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 641 " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\"," | 643 " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\"," |
| 642 " \"attribution\" : \"Foo News\"," | 644 " \"attribution\" : \"Foo News\"," |
| 643 " \"imageUrl\" : \"http://localhost/foobar.jpg\"," | 645 " \"imageUrl\" : \"http://localhost/foobar.jpg\"," |
| 644 " \"ampUrl\" : \"http://localhost/amp\"," | 646 " \"ampUrl\" : \"http://localhost/amp\"," |
| 645 " \"faviconUrl\" : \"http://localhost/favicon.ico\" " | 647 " \"faviconUrl\" : \"http://localhost/favicon.ico\" " |
| 646 " }]" | 648 " }]" |
| 647 "}]}"; | 649 "}]}"; |
| 648 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, | 650 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, |
| 649 net::URLRequestStatus::SUCCESS); | 651 net::URLRequestStatus::SUCCESS); |
| 650 EXPECT_CALL(mock_callback(), | 652 EXPECT_CALL(mock_callback(), |
| 651 Run(AllOf(IsSingleArticle("http://localhost/foobar"), | 653 Run(NTPSnippetsFetcher::FetchResult::SUCCESS, |
| 654 AllOf(IsSingleArticle("http://localhost/foobar"), | |
| 652 FirstCategoryHasInfo(IsCategoryInfoForArticles())))); | 655 FirstCategoryHasInfo(IsCategoryInfoForArticles())))); |
| 653 snippets_fetcher().FetchSnippets( | 656 snippets_fetcher().FetchSnippets( |
| 654 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 657 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 655 FastForwardUntilNoTasksRemain(); | 658 FastForwardUntilNoTasksRemain(); |
| 656 EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK")); | 659 EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK")); |
| 657 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); | 660 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); |
| 658 EXPECT_THAT(histogram_tester().GetAllSamples( | 661 EXPECT_THAT(histogram_tester().GetAllSamples( |
| 659 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), | 662 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), |
| 660 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); | 663 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); |
| 661 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), | 664 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), |
| 662 ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs, | 665 ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs, |
| 663 /*count=*/1))); | 666 /*count=*/1))); |
| 664 } | 667 } |
| 665 | 668 |
| 666 TEST_F(NTPSnippetsContentSuggestionsFetcherTest, EmptyCategoryIsOK) { | 669 TEST_F(NTPSnippetsContentSuggestionsFetcherTest, EmptyCategoryIsOK) { |
| 667 const std::string kJsonStr = | 670 const std::string kJsonStr = |
| 668 "{\"categories\" : [{" | 671 "{\"categories\" : [{" |
| 669 " \"id\": 1," | 672 " \"id\": 1," |
| 670 " \"localizedTitle\": \"Articles for You\"" | 673 " \"localizedTitle\": \"Articles for You\"" |
| 671 "}]}"; | 674 "}]}"; |
| 672 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, | 675 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, |
| 673 net::URLRequestStatus::SUCCESS); | 676 net::URLRequestStatus::SUCCESS); |
| 674 EXPECT_CALL(mock_callback(), Run(IsEmptyArticleList())); | 677 EXPECT_CALL(mock_callback(), Run(NTPSnippetsFetcher::FetchResult::SUCCESS, |
| 678 IsEmptyArticleList())); | |
| 675 snippets_fetcher().FetchSnippets( | 679 snippets_fetcher().FetchSnippets( |
| 676 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 680 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 677 FastForwardUntilNoTasksRemain(); | 681 FastForwardUntilNoTasksRemain(); |
| 678 EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK")); | 682 EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK")); |
| 679 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); | 683 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); |
| 680 EXPECT_THAT(histogram_tester().GetAllSamples( | 684 EXPECT_THAT(histogram_tester().GetAllSamples( |
| 681 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), | 685 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), |
| 682 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); | 686 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); |
| 683 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), | 687 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), |
| 684 ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs, | 688 ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs, |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 715 " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\"," | 719 " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\"," |
| 716 " \"attribution\" : \"Foo News\"," | 720 " \"attribution\" : \"Foo News\"," |
| 717 " \"imageUrl\" : \"http://localhost/foo2.jpg\"," | 721 " \"imageUrl\" : \"http://localhost/foo2.jpg\"," |
| 718 " \"ampUrl\" : \"http://localhost/amp\"," | 722 " \"ampUrl\" : \"http://localhost/amp\"," |
| 719 " \"faviconUrl\" : \"http://localhost/favicon.ico\" " | 723 " \"faviconUrl\" : \"http://localhost/favicon.ico\" " |
| 720 " }]" | 724 " }]" |
| 721 "}]}"; | 725 "}]}"; |
| 722 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, | 726 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, |
| 723 net::URLRequestStatus::SUCCESS); | 727 net::URLRequestStatus::SUCCESS); |
| 724 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories; | 728 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories; |
| 725 EXPECT_CALL(mock_callback(), Run(_)) | 729 EXPECT_CALL(mock_callback(), Run(NTPSnippetsFetcher::FetchResult::SUCCESS, _)) |
| 726 .WillOnce(MoveArgumentPointeeTo(&fetched_categories)); | 730 .WillOnce(MoveArgument1PointeeTo(&fetched_categories)); |
|
tschumann
2016/12/08 18:18:51
nit: the matcher name is now a bit hard to underst
| |
| 727 snippets_fetcher().FetchSnippets( | 731 snippets_fetcher().FetchSnippets( |
| 728 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 732 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 729 FastForwardUntilNoTasksRemain(); | 733 FastForwardUntilNoTasksRemain(); |
| 730 | 734 |
| 731 ASSERT_TRUE(fetched_categories); | 735 ASSERT_TRUE(fetched_categories); |
| 732 ASSERT_THAT(fetched_categories->size(), Eq(2u)); | 736 ASSERT_THAT(fetched_categories->size(), Eq(2u)); |
| 733 for (const auto& category : *fetched_categories) { | 737 for (const auto& category : *fetched_categories) { |
| 734 const auto& articles = category.snippets; | 738 const auto& articles = category.snippets; |
| 735 if (category.category.IsKnownCategory(KnownCategories::ARTICLES)) { | 739 if (category.category.IsKnownCategory(KnownCategories::ARTICLES)) { |
| 736 ASSERT_THAT(articles.size(), Eq(1u)); | 740 ASSERT_THAT(articles.size(), Eq(1u)); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 777 " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\"," | 781 " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\"," |
| 778 " \"attribution\" : \"Foo News\"," | 782 " \"attribution\" : \"Foo News\"," |
| 779 " \"imageUrl\" : \"http://localhost/foo2.jpg\"," | 783 " \"imageUrl\" : \"http://localhost/foo2.jpg\"," |
| 780 " \"ampUrl\" : \"http://localhost/amp\"," | 784 " \"ampUrl\" : \"http://localhost/amp\"," |
| 781 " \"faviconUrl\" : \"http://localhost/favicon.ico\" " | 785 " \"faviconUrl\" : \"http://localhost/favicon.ico\" " |
| 782 " }]" | 786 " }]" |
| 783 "}]}"; | 787 "}]}"; |
| 784 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, | 788 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, |
| 785 net::URLRequestStatus::SUCCESS); | 789 net::URLRequestStatus::SUCCESS); |
| 786 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories; | 790 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories; |
| 787 EXPECT_CALL(mock_callback(), Run(_)) | 791 EXPECT_CALL(mock_callback(), Run(NTPSnippetsFetcher::FetchResult::SUCCESS, _)) |
| 788 .WillOnce(MoveArgumentPointeeTo(&fetched_categories)); | 792 .WillOnce(MoveArgument1PointeeTo(&fetched_categories)); |
| 789 snippets_fetcher().FetchSnippets( | 793 snippets_fetcher().FetchSnippets( |
| 790 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 794 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 791 FastForwardUntilNoTasksRemain(); | 795 FastForwardUntilNoTasksRemain(); |
| 792 | 796 |
| 793 ASSERT_TRUE(fetched_categories); | 797 ASSERT_TRUE(fetched_categories); |
| 794 ASSERT_THAT(fetched_categories->size(), Eq(1u)); | 798 ASSERT_THAT(fetched_categories->size(), Eq(1u)); |
| 795 EXPECT_THAT(fetched_categories->front().info.has_more_action(), Eq(false)); | 799 EXPECT_THAT(fetched_categories->front().info.has_more_action(), Eq(false)); |
| 796 EXPECT_THAT(fetched_categories->front().info.title(), | 800 EXPECT_THAT(fetched_categories->front().info.title(), |
| 797 Eq(base::UTF8ToUTF16("Articles for Me"))); | 801 Eq(base::UTF8ToUTF16("Articles for Me"))); |
| 798 } | 802 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 841 " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\"," | 845 " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\"," |
| 842 " \"attribution\" : \"Foo News\"," | 846 " \"attribution\" : \"Foo News\"," |
| 843 " \"imageUrl\" : \"http://localhost/foo3.jpg\"," | 847 " \"imageUrl\" : \"http://localhost/foo3.jpg\"," |
| 844 " \"ampUrl\" : \"http://localhost/amp\"," | 848 " \"ampUrl\" : \"http://localhost/amp\"," |
| 845 " \"faviconUrl\" : \"http://localhost/favicon.ico\" " | 849 " \"faviconUrl\" : \"http://localhost/favicon.ico\" " |
| 846 " }]" | 850 " }]" |
| 847 "}]}"; | 851 "}]}"; |
| 848 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, | 852 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, |
| 849 net::URLRequestStatus::SUCCESS); | 853 net::URLRequestStatus::SUCCESS); |
| 850 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories; | 854 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories; |
| 851 EXPECT_CALL(mock_callback(), Run(_)) | 855 EXPECT_CALL(mock_callback(), Run(NTPSnippetsFetcher::FetchResult::SUCCESS, _)) |
| 852 .WillOnce(MoveArgumentPointeeTo(&fetched_categories)); | 856 .WillOnce(MoveArgument1PointeeTo(&fetched_categories)); |
| 853 | 857 |
| 854 NTPSnippetsFetcher::Params params = test_params(); | 858 NTPSnippetsFetcher::Params params = test_params(); |
| 855 params.exclusive_category = base::Optional<Category>( | 859 params.exclusive_category = base::Optional<Category>( |
| 856 CategoryFactory().FromRemoteCategory(2)); | 860 CategoryFactory().FromRemoteCategory(2)); |
| 857 snippets_fetcher().FetchSnippets( | 861 snippets_fetcher().FetchSnippets( |
| 858 params, ToSnippetsAvailableCallback(&mock_callback())); | 862 params, ToSnippetsAvailableCallback(&mock_callback())); |
| 859 FastForwardUntilNoTasksRemain(); | 863 FastForwardUntilNoTasksRemain(); |
| 860 | 864 |
| 861 ASSERT_TRUE(fetched_categories); | 865 ASSERT_TRUE(fetched_categories); |
| 862 ASSERT_THAT(fetched_categories->size(), Eq(1u)); | 866 ASSERT_THAT(fetched_categories->size(), Eq(1u)); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 885 SetFetchingPersonalizationVariation("both"); | 889 SetFetchingPersonalizationVariation("both"); |
| 886 ResetSnippetsFetcher(); | 890 ResetSnippetsFetcher(); |
| 887 EXPECT_THAT(snippets_fetcher().personalization(), | 891 EXPECT_THAT(snippets_fetcher().personalization(), |
| 888 Eq(NTPSnippetsFetcher::Personalization::kBoth)); | 892 Eq(NTPSnippetsFetcher::Personalization::kBoth)); |
| 889 } | 893 } |
| 890 | 894 |
| 891 TEST_F(NTPSnippetsFetcherTest, ShouldFetchSuccessfullyEmptyList) { | 895 TEST_F(NTPSnippetsFetcherTest, ShouldFetchSuccessfullyEmptyList) { |
| 892 const std::string kJsonStr = "{\"recos\": []}"; | 896 const std::string kJsonStr = "{\"recos\": []}"; |
| 893 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, | 897 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, |
| 894 net::URLRequestStatus::SUCCESS); | 898 net::URLRequestStatus::SUCCESS); |
| 895 EXPECT_CALL(mock_callback(), Run(IsEmptyArticleList())); | 899 EXPECT_CALL(mock_callback(), Run(NTPSnippetsFetcher::FetchResult::SUCCESS, |
| 900 IsEmptyArticleList())); | |
| 896 snippets_fetcher().FetchSnippets( | 901 snippets_fetcher().FetchSnippets( |
| 897 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 902 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 898 FastForwardUntilNoTasksRemain(); | 903 FastForwardUntilNoTasksRemain(); |
| 899 EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK")); | 904 EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK")); |
| 900 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); | 905 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); |
| 901 EXPECT_THAT( | 906 EXPECT_THAT( |
| 902 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), | 907 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), |
| 903 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1))); | 908 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1))); |
| 904 EXPECT_THAT(histogram_tester().GetAllSamples( | 909 EXPECT_THAT(histogram_tester().GetAllSamples( |
| 905 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), | 910 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 933 std::string content_selector_value; | 938 std::string content_selector_value; |
| 934 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value)); | 939 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value)); |
| 935 EXPECT_THAT(content_selector_value, Eq("www.somehost1.com")); | 940 EXPECT_THAT(content_selector_value, Eq("www.somehost1.com")); |
| 936 ASSERT_TRUE(content_selectors->GetDictionary(1, &content_selector)); | 941 ASSERT_TRUE(content_selectors->GetDictionary(1, &content_selector)); |
| 937 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value)); | 942 EXPECT_TRUE(content_selector->GetString("value", &content_selector_value)); |
| 938 EXPECT_THAT(content_selector_value, Eq("www.somehost2.com")); | 943 EXPECT_THAT(content_selector_value, Eq("www.somehost2.com")); |
| 939 // Call the delegate callback manually as the TestURLFetcher deletes any | 944 // Call the delegate callback manually as the TestURLFetcher deletes any |
| 940 // call to the delegate that usually happens on |Start|. | 945 // call to the delegate that usually happens on |Start|. |
| 941 // Without the call to the delegate, it leaks the request that owns itself. | 946 // Without the call to the delegate, it leaks the request that owns itself. |
| 942 ASSERT_THAT(fetcher->delegate(), NotNull()); | 947 ASSERT_THAT(fetcher->delegate(), NotNull()); |
| 943 EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1); | 948 EXPECT_CALL(mock_callback(), |
| 949 Run(NTPSnippetsFetcher::FetchResult::URL_REQUEST_STATUS_ERROR, | |
| 950 /*snippets=*/Not(HasValue()))) | |
| 951 .Times(1); | |
| 944 // An 4XX response needs the least configuration to successfully invoke the | 952 // An 4XX response needs the least configuration to successfully invoke the |
| 945 // callback properly as the results are not important in this test. | 953 // callback properly as the results are not important in this test. |
| 946 fetcher->set_response_code(net::HTTP_NOT_FOUND); | 954 fetcher->set_response_code(net::HTTP_NOT_FOUND); |
| 947 fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED, -2)); | 955 fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED, -2)); |
| 948 fetcher->delegate()->OnURLFetchComplete(fetcher); | 956 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 949 } | 957 } |
| 950 | 958 |
| 951 TEST_F(NTPSnippetsFetcherTest, ShouldReportUrlStatusError) { | 959 TEST_F(NTPSnippetsFetcherTest, ShouldReportUrlStatusError) { |
| 952 SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND, | 960 SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND, |
| 953 net::URLRequestStatus::FAILED); | 961 net::URLRequestStatus::FAILED); |
| 954 EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1); | 962 EXPECT_CALL(mock_callback(), |
| 963 Run(NTPSnippetsFetcher::FetchResult::URL_REQUEST_STATUS_ERROR, | |
| 964 /*snippets=*/Not(HasValue()))) | |
| 965 .Times(1); | |
|
tschumann
2016/12/08 18:18:51
nit: Times(1) can be omitted -- it's the default (
| |
| 955 snippets_fetcher().FetchSnippets( | 966 snippets_fetcher().FetchSnippets( |
| 956 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 967 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 957 FastForwardUntilNoTasksRemain(); | 968 FastForwardUntilNoTasksRemain(); |
| 958 EXPECT_THAT(snippets_fetcher().last_status(), | 969 EXPECT_THAT(snippets_fetcher().last_status(), |
| 959 Eq("URLRequestStatus error -2")); | 970 Eq("URLRequestStatus error -2")); |
| 960 EXPECT_THAT(snippets_fetcher().last_json(), IsEmpty()); | 971 EXPECT_THAT(snippets_fetcher().last_json(), IsEmpty()); |
| 961 EXPECT_THAT( | 972 EXPECT_THAT( |
| 962 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), | 973 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), |
| 963 ElementsAre(base::Bucket(/*min=*/2, /*count=*/1))); | 974 ElementsAre(base::Bucket(/*min=*/2, /*count=*/1))); |
| 964 EXPECT_THAT(histogram_tester().GetAllSamples( | 975 EXPECT_THAT(histogram_tester().GetAllSamples( |
| 965 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), | 976 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), |
| 966 ElementsAre(base::Bucket(/*min=*/-2, /*count=*/1))); | 977 ElementsAre(base::Bucket(/*min=*/-2, /*count=*/1))); |
| 967 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), | 978 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), |
| 968 Not(IsEmpty())); | 979 Not(IsEmpty())); |
| 969 } | 980 } |
| 970 | 981 |
| 971 TEST_F(NTPSnippetsFetcherTest, ShouldReportHttpError) { | 982 TEST_F(NTPSnippetsFetcherTest, ShouldReportHttpError) { |
| 972 SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND, | 983 SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND, |
| 973 net::URLRequestStatus::SUCCESS); | 984 net::URLRequestStatus::SUCCESS); |
| 974 EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1); | 985 EXPECT_CALL(mock_callback(), Run(NTPSnippetsFetcher::FetchResult::HTTP_ERROR, |
| 986 /*snippets=*/Not(HasValue()))) | |
| 987 .Times(1); | |
| 975 snippets_fetcher().FetchSnippets( | 988 snippets_fetcher().FetchSnippets( |
| 976 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 989 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 977 FastForwardUntilNoTasksRemain(); | 990 FastForwardUntilNoTasksRemain(); |
| 978 EXPECT_THAT(snippets_fetcher().last_json(), IsEmpty()); | 991 EXPECT_THAT(snippets_fetcher().last_json(), IsEmpty()); |
| 979 EXPECT_THAT( | 992 EXPECT_THAT( |
| 980 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), | 993 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), |
| 981 ElementsAre(base::Bucket(/*min=*/3, /*count=*/1))); | 994 ElementsAre(base::Bucket(/*min=*/3, /*count=*/1))); |
| 982 EXPECT_THAT(histogram_tester().GetAllSamples( | 995 EXPECT_THAT(histogram_tester().GetAllSamples( |
| 983 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), | 996 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), |
| 984 ElementsAre(base::Bucket(/*min=*/404, /*count=*/1))); | 997 ElementsAre(base::Bucket(/*min=*/404, /*count=*/1))); |
| 985 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), | 998 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), |
| 986 Not(IsEmpty())); | 999 Not(IsEmpty())); |
| 987 } | 1000 } |
| 988 | 1001 |
| 989 TEST_F(NTPSnippetsFetcherTest, ShouldReportJsonError) { | 1002 TEST_F(NTPSnippetsFetcherTest, ShouldReportJsonError) { |
| 990 const std::string kInvalidJsonStr = "{ \"recos\": []"; | 1003 const std::string kInvalidJsonStr = "{ \"recos\": []"; |
| 991 SetFakeResponse(/*response_data=*/kInvalidJsonStr, net::HTTP_OK, | 1004 SetFakeResponse(/*response_data=*/kInvalidJsonStr, net::HTTP_OK, |
| 992 net::URLRequestStatus::SUCCESS); | 1005 net::URLRequestStatus::SUCCESS); |
| 993 EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1); | 1006 EXPECT_CALL(mock_callback(), |
| 1007 Run(NTPSnippetsFetcher::FetchResult::JSON_PARSE_ERROR, | |
| 1008 /*snippets=*/Not(HasValue()))) | |
| 1009 .Times(1); | |
| 994 snippets_fetcher().FetchSnippets( | 1010 snippets_fetcher().FetchSnippets( |
| 995 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 1011 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 996 FastForwardUntilNoTasksRemain(); | 1012 FastForwardUntilNoTasksRemain(); |
| 997 EXPECT_THAT(snippets_fetcher().last_status(), | 1013 EXPECT_THAT(snippets_fetcher().last_status(), |
| 998 StartsWith("Received invalid JSON (error ")); | 1014 StartsWith("Received invalid JSON (error ")); |
| 999 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kInvalidJsonStr)); | 1015 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kInvalidJsonStr)); |
| 1000 EXPECT_THAT( | 1016 EXPECT_THAT( |
| 1001 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), | 1017 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), |
| 1002 ElementsAre(base::Bucket(/*min=*/4, /*count=*/1))); | 1018 ElementsAre(base::Bucket(/*min=*/4, /*count=*/1))); |
| 1003 EXPECT_THAT(histogram_tester().GetAllSamples( | 1019 EXPECT_THAT(histogram_tester().GetAllSamples( |
| 1004 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), | 1020 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), |
| 1005 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); | 1021 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); |
| 1006 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), | 1022 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), |
| 1007 ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs, | 1023 ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs, |
| 1008 /*count=*/1))); | 1024 /*count=*/1))); |
| 1009 } | 1025 } |
| 1010 | 1026 |
| 1011 TEST_F(NTPSnippetsFetcherTest, ShouldReportJsonErrorForEmptyResponse) { | 1027 TEST_F(NTPSnippetsFetcherTest, ShouldReportJsonErrorForEmptyResponse) { |
| 1012 SetFakeResponse(/*response_data=*/std::string(), net::HTTP_OK, | 1028 SetFakeResponse(/*response_data=*/std::string(), net::HTTP_OK, |
| 1013 net::URLRequestStatus::SUCCESS); | 1029 net::URLRequestStatus::SUCCESS); |
| 1014 EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1); | 1030 EXPECT_CALL(mock_callback(), |
| 1031 Run(NTPSnippetsFetcher::FetchResult::JSON_PARSE_ERROR, | |
| 1032 /*snippets=*/Not(HasValue()))) | |
| 1033 .Times(1); | |
| 1015 snippets_fetcher().FetchSnippets( | 1034 snippets_fetcher().FetchSnippets( |
| 1016 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 1035 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 1017 FastForwardUntilNoTasksRemain(); | 1036 FastForwardUntilNoTasksRemain(); |
| 1018 EXPECT_THAT(snippets_fetcher().last_json(), std::string()); | 1037 EXPECT_THAT(snippets_fetcher().last_json(), std::string()); |
| 1019 EXPECT_THAT( | 1038 EXPECT_THAT( |
| 1020 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), | 1039 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), |
| 1021 ElementsAre(base::Bucket(/*min=*/4, /*count=*/1))); | 1040 ElementsAre(base::Bucket(/*min=*/4, /*count=*/1))); |
| 1022 EXPECT_THAT(histogram_tester().GetAllSamples( | 1041 EXPECT_THAT(histogram_tester().GetAllSamples( |
| 1023 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), | 1042 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), |
| 1024 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); | 1043 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); |
| 1025 } | 1044 } |
| 1026 | 1045 |
| 1027 TEST_F(NTPSnippetsFetcherTest, ShouldReportInvalidListError) { | 1046 TEST_F(NTPSnippetsFetcherTest, ShouldReportInvalidListError) { |
| 1028 const std::string kJsonStr = | 1047 const std::string kJsonStr = |
| 1029 "{\"recos\": [{ \"contentInfo\": { \"foo\" : \"bar\" }}]}"; | 1048 "{\"recos\": [{ \"contentInfo\": { \"foo\" : \"bar\" }}]}"; |
| 1030 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, | 1049 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, |
| 1031 net::URLRequestStatus::SUCCESS); | 1050 net::URLRequestStatus::SUCCESS); |
| 1032 EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1); | 1051 EXPECT_CALL( |
| 1052 mock_callback(), | |
| 1053 Run(NTPSnippetsFetcher::FetchResult::INVALID_SNIPPET_CONTENT_ERROR, | |
| 1054 /*snippets=*/Not(HasValue()))) | |
| 1055 .Times(1); | |
| 1033 snippets_fetcher().FetchSnippets( | 1056 snippets_fetcher().FetchSnippets( |
| 1034 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 1057 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 1035 FastForwardUntilNoTasksRemain(); | 1058 FastForwardUntilNoTasksRemain(); |
| 1036 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); | 1059 EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr)); |
| 1037 EXPECT_THAT( | 1060 EXPECT_THAT( |
| 1038 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), | 1061 histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), |
| 1039 ElementsAre(base::Bucket(/*min=*/5, /*count=*/1))); | 1062 ElementsAre(base::Bucket(/*min=*/5, /*count=*/1))); |
| 1040 EXPECT_THAT(histogram_tester().GetAllSamples( | 1063 EXPECT_THAT(histogram_tester().GetAllSamples( |
| 1041 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), | 1064 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), |
| 1042 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); | 1065 ElementsAre(base::Bucket(/*min=*/200, /*count=*/1))); |
| 1043 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), | 1066 EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), |
| 1044 Not(IsEmpty())); | 1067 Not(IsEmpty())); |
| 1045 } | 1068 } |
| 1046 | 1069 |
| 1047 // This test actually verifies that the test setup itself is sane, to prevent | 1070 // This test actually verifies that the test setup itself is sane, to prevent |
| 1048 // hard-to-reproduce test failures. | 1071 // hard-to-reproduce test failures. |
| 1049 TEST_F(NTPSnippetsFetcherTest, ShouldReportHttpErrorForMissingBakedResponse) { | 1072 TEST_F(NTPSnippetsFetcherTest, ShouldReportHttpErrorForMissingBakedResponse) { |
| 1050 InitFakeURLFetcherFactory(); | 1073 InitFakeURLFetcherFactory(); |
| 1051 EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1); | 1074 EXPECT_CALL(mock_callback(), |
| 1075 Run(NTPSnippetsFetcher::FetchResult::URL_REQUEST_STATUS_ERROR, | |
| 1076 /*snippets=*/Not(HasValue()))) | |
| 1077 .Times(1); | |
| 1052 snippets_fetcher().FetchSnippets( | 1078 snippets_fetcher().FetchSnippets( |
| 1053 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 1079 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 1054 FastForwardUntilNoTasksRemain(); | 1080 FastForwardUntilNoTasksRemain(); |
| 1055 } | 1081 } |
| 1056 | 1082 |
| 1057 TEST_F(NTPSnippetsFetcherTest, ShouldProcessConcurrentFetches) { | 1083 TEST_F(NTPSnippetsFetcherTest, ShouldProcessConcurrentFetches) { |
| 1058 const std::string kJsonStr = "{ \"recos\": [] }"; | 1084 const std::string kJsonStr = "{ \"recos\": [] }"; |
| 1059 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, | 1085 SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK, |
| 1060 net::URLRequestStatus::SUCCESS); | 1086 net::URLRequestStatus::SUCCESS); |
| 1061 EXPECT_CALL(mock_callback(), Run(IsEmptyArticleList())).Times(5); | 1087 EXPECT_CALL(mock_callback(), Run(NTPSnippetsFetcher::FetchResult::SUCCESS, |
| 1088 IsEmptyArticleList())) | |
| 1089 .Times(5); | |
| 1062 snippets_fetcher().FetchSnippets( | 1090 snippets_fetcher().FetchSnippets( |
| 1063 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 1091 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 1064 // More calls to FetchSnippets() do not interrupt the previous. | 1092 // More calls to FetchSnippets() do not interrupt the previous. |
| 1065 // Callback is expected to be called once each time. | 1093 // Callback is expected to be called once each time. |
| 1066 snippets_fetcher().FetchSnippets( | 1094 snippets_fetcher().FetchSnippets( |
| 1067 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 1095 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 1068 snippets_fetcher().FetchSnippets( | 1096 snippets_fetcher().FetchSnippets( |
| 1069 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 1097 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| 1070 snippets_fetcher().FetchSnippets( | 1098 snippets_fetcher().FetchSnippets( |
| 1071 test_params(), ToSnippetsAvailableCallback(&mock_callback())); | 1099 test_params(), ToSnippetsAvailableCallback(&mock_callback())); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 1088 const NTPSnippetsFetcher::OptionalFetchedCategories& fetched_categories) { | 1116 const NTPSnippetsFetcher::OptionalFetchedCategories& fetched_categories) { |
| 1089 if (fetched_categories) { | 1117 if (fetched_categories) { |
| 1090 // Matchers above aren't any more precise than this, so this is sufficient | 1118 // Matchers above aren't any more precise than this, so this is sufficient |
| 1091 // for test-failure diagnostics. | 1119 // for test-failure diagnostics. |
| 1092 return os << "list with " << fetched_categories->size() << " elements"; | 1120 return os << "list with " << fetched_categories->size() << " elements"; |
| 1093 } | 1121 } |
| 1094 return os << "null"; | 1122 return os << "null"; |
| 1095 } | 1123 } |
| 1096 | 1124 |
| 1097 } // namespace ntp_snippets | 1125 } // namespace ntp_snippets |
| OLD | NEW |