search_result_list_view_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/app_list/views/search_result_list_view.h"
  5. #include <stddef.h>
  6. #include <map>
  7. #include <memory>
  8. #include <utility>
  9. #include "ash/app_list/app_list_test_view_delegate.h"
  10. #include "ash/app_list/model/search/search_model.h"
  11. #include "ash/app_list/model/search/test_search_result.h"
  12. #include "ash/app_list/views/search_result_view.h"
  13. #include "ash/constants/ash_features.h"
  14. #include "ash/public/cpp/app_list/app_list_features.h"
  15. #include "ash/public/cpp/test/test_app_list_color_provider.h"
  16. #include "base/strings/stringprintf.h"
  17. #include "base/strings/utf_string_conversions.h"
  18. #include "base/test/scoped_feature_list.h"
  19. #include "ui/views/test/views_test_base.h"
  20. #include "ui/views/test/widget_test.h"
  21. namespace ash {
  22. namespace test {
  23. namespace {
  24. int kDefaultSearchItems = 3;
  25. // Preferred sizing for different types of search result views.
  26. constexpr int kPreferredWidth = 640;
  27. constexpr int kClassicViewHeight = 48;
  28. constexpr int kDefaultViewHeight = 40;
  29. constexpr int kInlineAnswerViewHeight = 80;
  30. constexpr gfx::Insets kInlineAnswerBorder(12);
  31. // SearchResultListType::kUnified, SearchResultListType::AnswerCard, and
  32. // SearchResultListType::kBestMatch do not have associated categories.
  33. constexpr int num_list_types_not_in_category = 3;
  34. // SearchResult::Category::kUnknown does not have an associated list type.
  35. constexpr int num_category_without_list_type = 1;
  36. // SearchResultListType::kUnified is used for categorical search.
  37. constexpr int num_list_types_not_used_for_categorical_search = 1;
  38. } // namespace
  39. class SearchResultListViewTest : public views::test::WidgetTest,
  40. public testing::WithParamInterface<bool> {
  41. public:
  42. SearchResultListViewTest() = default;
  43. SearchResultListViewTest(const SearchResultListViewTest&) = delete;
  44. SearchResultListViewTest& operator=(const SearchResultListViewTest&) = delete;
  45. ~SearchResultListViewTest() override = default;
  46. // Overridden from testing::Test:
  47. void SetUp() override {
  48. scoped_feature_list_.InitWithFeatureState(features::kProductivityLauncher,
  49. IsProductivityLauncherEnabled());
  50. views::test::WidgetTest::SetUp();
  51. widget_ = CreateTopLevelPlatformWidget();
  52. unified_view_ = std::make_unique<SearchResultListView>(
  53. nullptr, &view_delegate_, nullptr,
  54. SearchResultView::SearchResultViewType::kClassic, false, absl::nullopt);
  55. unified_view_->SetListType(
  56. SearchResultListView::SearchResultListType::kUnified);
  57. default_view_ = std::make_unique<SearchResultListView>(
  58. nullptr, &view_delegate_, nullptr,
  59. SearchResultView::SearchResultViewType::kDefault, true, absl::nullopt);
  60. default_view_->SetListType(
  61. SearchResultListView::SearchResultListType::kBestMatch);
  62. answer_card_view_ = std::make_unique<SearchResultListView>(
  63. nullptr, &view_delegate_, nullptr,
  64. SearchResultView::SearchResultViewType::kAnswerCard, true,
  65. absl::nullopt);
  66. answer_card_view_->SetListType(
  67. SearchResultListView::SearchResultListType::kAnswerCard);
  68. widget_->SetBounds(gfx::Rect(0, 0, 700, 500));
  69. widget_->GetContentsView()->AddChildView(unified_view_.get());
  70. widget_->GetContentsView()->AddChildView(default_view_.get());
  71. widget_->GetContentsView()->AddChildView(answer_card_view_.get());
  72. widget_->Show();
  73. unified_view_->SetResults(GetResults());
  74. default_view_->SetResults(GetResults());
  75. answer_card_view_->SetResults(GetResults());
  76. }
  77. void TearDown() override {
  78. unified_view_.reset();
  79. default_view_.reset();
  80. answer_card_view_.reset();
  81. widget_->CloseNow();
  82. views::test::WidgetTest::TearDown();
  83. }
  84. protected:
  85. bool IsProductivityLauncherEnabled() const { return GetParam(); }
  86. SearchResultListView* unified_view() const { return unified_view_.get(); }
  87. SearchResultListView* default_view() const { return default_view_.get(); }
  88. SearchResultListView* answer_card_view() const {
  89. return answer_card_view_.get();
  90. }
  91. SearchResultView* GetUnifiedResultViewAt(int index) const {
  92. return unified_view_->GetResultViewAt(index);
  93. }
  94. SearchResultView* GetDefaultResultViewAt(int index) const {
  95. return default_view_->GetResultViewAt(index);
  96. }
  97. SearchResultView* GetAnswerCardResultViewAt(int index) const {
  98. return answer_card_view_->GetResultViewAt(index);
  99. }
  100. std::vector<SearchResultView*> GetAssistantResultViews() const {
  101. std::vector<SearchResultView*> results;
  102. for (auto* view : unified_view_->search_result_views_) {
  103. auto* result = view->result();
  104. if (result &&
  105. result->result_type() == AppListSearchResultType::kAssistantText)
  106. results.push_back(view);
  107. }
  108. return results;
  109. }
  110. SearchModel::SearchResults* GetResults() {
  111. return AppListModelProvider::Get()->search_model()->results();
  112. }
  113. void AddAssistantSearchResult() {
  114. SearchModel::SearchResults* results = GetResults();
  115. std::unique_ptr<TestSearchResult> assistant_result =
  116. std::make_unique<TestSearchResult>();
  117. assistant_result->set_result_type(
  118. ash::AppListSearchResultType::kAssistantText);
  119. assistant_result->set_display_type(ash::SearchResultDisplayType::kList);
  120. assistant_result->SetTitle(u"assistant result");
  121. results->Add(std::move(assistant_result));
  122. RunPendingMessages();
  123. }
  124. void SetUpSearchResults() {
  125. SearchModel::SearchResults* results = GetResults();
  126. for (int i = 0; i < kDefaultSearchItems; ++i) {
  127. std::unique_ptr<TestSearchResult> result =
  128. std::make_unique<TestSearchResult>();
  129. result->set_display_type(ash::SearchResultDisplayType::kList);
  130. result->SetTitle(base::UTF8ToUTF16(base::StringPrintf("Result %d", i)));
  131. result->set_best_match(true);
  132. if (i < 2)
  133. result->SetDetails(u"Detail");
  134. results->Add(std::move(result));
  135. }
  136. // Adding results will schedule Update().
  137. RunPendingMessages();
  138. }
  139. int GetOpenResultCountAndReset(int ranking) {
  140. EXPECT_GT(view_delegate_.open_search_result_counts().count(ranking), 0u);
  141. int result = view_delegate_.open_search_result_counts()[ranking];
  142. view_delegate_.open_search_result_counts().clear();
  143. return result;
  144. }
  145. int GetUnifiedViewResultCount() const { return unified_view_->num_results(); }
  146. void AddTestResult() {
  147. std::unique_ptr<TestSearchResult> result =
  148. std::make_unique<TestSearchResult>();
  149. result->set_display_type(ash::SearchResultDisplayType::kList);
  150. result->set_best_match(true);
  151. GetResults()->Add(std::move(result));
  152. }
  153. void DeleteResultAt(int index) { GetResults()->DeleteAt(index); }
  154. bool KeyPress(ui::KeyboardCode key_code) {
  155. ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
  156. return unified_view_->OnKeyPressed(event);
  157. }
  158. void ExpectConsistent() {
  159. RunPendingMessages();
  160. SearchModel::SearchResults* results = GetResults();
  161. for (size_t i = 0; i < results->item_count(); ++i) {
  162. SearchResultView* result_view = IsProductivityLauncherEnabled()
  163. ? GetDefaultResultViewAt(i)
  164. : GetUnifiedResultViewAt(i);
  165. ASSERT_TRUE(result_view) << "result view at " << i;
  166. EXPECT_EQ(results->GetItemAt(i), result_view->result());
  167. }
  168. }
  169. void DoUpdate() { unified_view()->DoUpdate(); }
  170. private:
  171. base::test::ScopedFeatureList scoped_feature_list_;
  172. TestAppListColorProvider color_provider_; // Needed by AppListView.
  173. AppListTestViewDelegate view_delegate_;
  174. std::unique_ptr<SearchResultListView> unified_view_;
  175. std::unique_ptr<SearchResultListView> default_view_;
  176. std::unique_ptr<SearchResultListView> answer_card_view_;
  177. views::Widget* widget_;
  178. };
  179. // Run search result list view tests with and without productivity launcher
  180. // enabled.
  181. INSTANTIATE_TEST_SUITE_P(All, SearchResultListViewTest, testing::Bool());
  182. TEST_P(SearchResultListViewTest, SpokenFeedback) {
  183. SetUpSearchResults();
  184. // Result 0 has a detail text. Expect that the detail is appended to the
  185. // accessibility name.
  186. EXPECT_EQ(u"Result 0, Detail",
  187. GetUnifiedResultViewAt(0)->ComputeAccessibleName());
  188. // Result 2 has no detail text.
  189. EXPECT_EQ(u"Result 2", GetUnifiedResultViewAt(2)->ComputeAccessibleName());
  190. }
  191. TEST_P(SearchResultListViewTest, CorrectEnumLength) {
  192. EXPECT_EQ(
  193. // Check that all types except for SearchResultListType::kUnified are
  194. // included in GetAllListTypesForCategoricalSearch.
  195. static_cast<int>(SearchResultListView::SearchResultListType::kMaxValue) +
  196. 1 /*0 indexing offset*/,
  197. static_cast<int>(
  198. SearchResultListView::GetAllListTypesForCategoricalSearch().size() +
  199. num_list_types_not_used_for_categorical_search));
  200. // Check that all types in AppListSearchResultCategory are included in
  201. // SearchResultListType.
  202. EXPECT_EQ(
  203. static_cast<int>(SearchResultListView::SearchResultListType::kMaxValue) +
  204. 1 /*0 indexing offset*/ - num_list_types_not_in_category,
  205. static_cast<int>(SearchResult::Category::kMaxValue) +
  206. 1 /*0 indexing offset*/ - num_category_without_list_type);
  207. }
  208. TEST_P(SearchResultListViewTest, SearchResultViewLayout) {
  209. // Set SearchResultListView bounds and check views are default size.
  210. unified_view()->SetBounds(0, 0, kPreferredWidth, 400);
  211. SetUpSearchResults();
  212. EXPECT_EQ(gfx::Size(kPreferredWidth, kClassicViewHeight),
  213. GetUnifiedResultViewAt(0)->size());
  214. EXPECT_EQ(gfx::Size(kPreferredWidth, kClassicViewHeight),
  215. GetUnifiedResultViewAt(1)->size());
  216. EXPECT_EQ(gfx::Size(kPreferredWidth, kClassicViewHeight),
  217. GetUnifiedResultViewAt(2)->size());
  218. // Override search result types.
  219. GetUnifiedResultViewAt(0)->SetSearchResultViewType(
  220. SearchResultView::SearchResultViewType::kClassic);
  221. GetUnifiedResultViewAt(1)->SetSearchResultViewType(
  222. SearchResultView::SearchResultViewType::kAnswerCard);
  223. GetUnifiedResultViewAt(2)->SetSearchResultViewType(
  224. SearchResultView::SearchResultViewType::kDefault);
  225. DoUpdate();
  226. EXPECT_EQ(gfx::Size(kPreferredWidth, kClassicViewHeight),
  227. GetUnifiedResultViewAt(0)->size());
  228. EXPECT_EQ(GetUnifiedResultViewAt(0)->TitleAndDetailsOrientationForTest(),
  229. views::LayoutOrientation::kVertical);
  230. EXPECT_EQ(gfx::Size(kPreferredWidth, kInlineAnswerViewHeight),
  231. GetUnifiedResultViewAt(1)->size());
  232. EXPECT_EQ(GetUnifiedResultViewAt(1)->TitleAndDetailsOrientationForTest(),
  233. views::LayoutOrientation::kVertical);
  234. EXPECT_EQ(gfx::Size(kPreferredWidth, kDefaultViewHeight),
  235. GetUnifiedResultViewAt(2)->size());
  236. EXPECT_EQ(GetUnifiedResultViewAt(2)->TitleAndDetailsOrientationForTest(),
  237. views::LayoutOrientation::kHorizontal);
  238. }
  239. TEST_P(SearchResultListViewTest, BorderTest) {
  240. unified_view()->SetBounds(0, 0, kPreferredWidth, 400);
  241. SetUpSearchResults();
  242. DoUpdate();
  243. EXPECT_EQ(kInlineAnswerBorder,
  244. GetAnswerCardResultViewAt(0)->GetBorder()->GetInsets());
  245. EXPECT_EQ(gfx::Insets(), GetUnifiedResultViewAt(0)->GetBorder()->GetInsets());
  246. EXPECT_EQ(gfx::Insets(), GetDefaultResultViewAt(0)->GetBorder()->GetInsets());
  247. }
  248. TEST_P(SearchResultListViewTest, ModelObservers) {
  249. SetUpSearchResults();
  250. ExpectConsistent();
  251. // Remove from end.
  252. DeleteResultAt(kDefaultSearchItems - 1);
  253. ExpectConsistent();
  254. AddTestResult();
  255. ExpectConsistent();
  256. // Remove from end.
  257. DeleteResultAt(kDefaultSearchItems - 1);
  258. ExpectConsistent();
  259. AddTestResult();
  260. ExpectConsistent();
  261. // Delete from start.
  262. DeleteResultAt(0);
  263. ExpectConsistent();
  264. }
  265. TEST_P(SearchResultListViewTest, HidesAssistantResultWhenTilesVisible) {
  266. SetUpSearchResults();
  267. // No assistant results available.
  268. EXPECT_TRUE(GetAssistantResultViews().empty());
  269. AddAssistantSearchResult();
  270. // Assistant result should be set and visible.
  271. for (const auto* view : GetAssistantResultViews()) {
  272. EXPECT_TRUE(view->GetVisible());
  273. EXPECT_EQ(view->result()->title(), u"assistant result");
  274. }
  275. // Add a tile result
  276. std::unique_ptr<TestSearchResult> tile_result =
  277. std::make_unique<TestSearchResult>();
  278. tile_result->set_display_type(ash::SearchResultDisplayType::kTile);
  279. GetResults()->Add(std::move(tile_result));
  280. RunPendingMessages();
  281. // Assistant result should be gone.
  282. EXPECT_TRUE(GetAssistantResultViews().empty());
  283. }
  284. } // namespace test
  285. } // namespace ash