1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18package com.android.settings.search; 19 20import static com.google.common.truth.Truth.assertThat; 21import static org.mockito.Matchers.any; 22import static org.mockito.Matchers.anyString; 23import static org.mockito.Mockito.never; 24import static org.mockito.Mockito.times; 25import static org.mockito.Mockito.verify; 26import static org.mockito.Mockito.when; 27 28import android.app.Activity; 29import android.content.Context; 30import android.content.Intent; 31import android.graphics.drawable.Drawable; 32import android.util.Pair; 33import android.view.ViewGroup; 34import android.widget.FrameLayout; 35 36import com.android.settings.R; 37import com.android.settings.TestConfig; 38import com.android.settings.search.SearchResult.Builder; 39import com.android.settings.search.ranking.SearchResultsRankerCallback; 40import com.android.settings.testutils.SettingsRobolectricTestRunner; 41 42import org.junit.Before; 43import org.junit.Test; 44import org.junit.runner.RunWith; 45import org.mockito.ArgumentCaptor; 46import org.mockito.Captor; 47import org.mockito.Mock; 48import org.mockito.MockitoAnnotations; 49import org.robolectric.Robolectric; 50import org.robolectric.annotation.Config; 51import org.robolectric.shadows.ShadowLooper; 52 53import java.util.ArrayList; 54import java.util.Arrays; 55import java.util.HashSet; 56import java.util.List; 57import java.util.Objects; 58import java.util.Set; 59 60@RunWith(SettingsRobolectricTestRunner.class) 61@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) 62public class SearchResultsAdapterTest { 63 64 @Mock 65 private SearchFragment mFragment; 66 @Mock 67 private SearchFeatureProvider mSearchFeatureProvider; 68 @Mock 69 private Context mMockContext; 70 @Captor 71 private ArgumentCaptor<Integer> mSearchResultsCountCaptor = 72 ArgumentCaptor.forClass(Integer.class); 73 private SearchResultsAdapter mAdapter; 74 private Context mContext; 75 private String mLoaderClassName; 76 77 private String[] TITLES = {"alpha", "bravo", "charlie", "appAlpha", "appBravo", "appCharlie"}; 78 79 @Before 80 public void setUp() { 81 MockitoAnnotations.initMocks(this); 82 mContext = Robolectric.buildActivity(Activity.class).get(); 83 mLoaderClassName = DatabaseResultLoader.class.getName(); 84 when(mFragment.getContext()).thenReturn(mMockContext); 85 when(mMockContext.getApplicationContext()).thenReturn(mContext); 86 when(mSearchFeatureProvider.smartSearchRankingTimeoutMs(any(Context.class))) 87 .thenReturn(300L); 88 mAdapter = new SearchResultsAdapter(mFragment, mSearchFeatureProvider); 89 } 90 91 @Test 92 public void testNoResultsAdded_emptyListReturned() { 93 List<SearchResult> updatedResults = mAdapter.getSearchResults(); 94 assertThat(updatedResults).isEmpty(); 95 } 96 97 @Test 98 public void testSingleSourceMerge_exactCopyReturned() { 99 Set<SearchResult> intentResults = getIntentSampleResults(); 100 mAdapter.initializeSearch(""); 101 mAdapter.addSearchResults(intentResults, mLoaderClassName); 102 mAdapter.notifyResultsLoaded(); 103 104 List<SearchResult> updatedResults = mAdapter.getSearchResults(); 105 assertThat(updatedResults).containsAllIn(intentResults); 106 } 107 108 @Test 109 public void testCreateViewHolder_returnsIntentResult() { 110 ViewGroup group = new FrameLayout(mContext); 111 SearchViewHolder view = mAdapter.onCreateViewHolder(group, 112 ResultPayload.PayloadType.INTENT); 113 assertThat(view).isInstanceOf(IntentSearchViewHolder.class); 114 } 115 116 @Test 117 public void testCreateViewHolder_returnsIntentSwitchResult() { 118 // TODO (b/62807132) test for InlineResult 119 ViewGroup group = new FrameLayout(mContext); 120 SearchViewHolder view = mAdapter.onCreateViewHolder(group, 121 ResultPayload.PayloadType.INLINE_SWITCH); 122 assertThat(view).isInstanceOf(IntentSearchViewHolder.class); 123 } 124 125 @Test 126 public void testEndToEndSearch_properResultsMerged_correctOrder() { 127 mAdapter.initializeSearch(""); 128 mAdapter.addSearchResults(new HashSet<>(getDummyAppResults()), 129 InstalledAppResultLoader.class.getName()); 130 mAdapter.addSearchResults(new HashSet<>(getDummyDbResults()), 131 DatabaseResultLoader.class.getName()); 132 mAdapter.notifyResultsLoaded(); 133 134 List<SearchResult> results = mAdapter.getSearchResults(); 135 assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha 136 assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha 137 assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo 138 assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo 139 assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie 140 assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie 141 verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture()); 142 assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6); 143 } 144 145 @Test 146 public void testEndToEndSearch_addResults_resultsAddedInOrder() { 147 List<SearchResult> appResults = getDummyAppResults(); 148 List<SearchResult> dbResults = getDummyDbResults(); 149 mAdapter.initializeSearch(""); 150 // Add two individual items 151 mAdapter.addSearchResults(new HashSet<>(appResults.subList(0, 1)), 152 InstalledAppResultLoader.class.getName()); 153 mAdapter.addSearchResults(new HashSet<>(dbResults.subList(0, 1)), 154 DatabaseResultLoader.class.getName()); 155 mAdapter.notifyResultsLoaded(); 156 // Add super-set of items 157 mAdapter.initializeSearch(""); 158 mAdapter.addSearchResults( 159 new HashSet<>(appResults), InstalledAppResultLoader.class.getName()); 160 mAdapter.addSearchResults( 161 new HashSet<>(dbResults), DatabaseResultLoader.class.getName()); 162 mAdapter.notifyResultsLoaded(); 163 164 List<SearchResult> results = mAdapter.getSearchResults(); 165 assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha 166 assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha 167 assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo 168 assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo 169 assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie 170 assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie 171 verify(mFragment, times(2)).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture()); 172 assertThat(mSearchResultsCountCaptor.getAllValues().toArray()) 173 .isEqualTo(new Integer[] {2, 6}); 174 } 175 176 @Test 177 public void testEndToEndSearch_removeResults_resultsAdded() { 178 List<SearchResult> appResults = getDummyAppResults(); 179 List<SearchResult> dbResults = getDummyDbResults(); 180 // Add list of items 181 mAdapter.initializeSearch(""); 182 mAdapter.addSearchResults(new HashSet<>(appResults), 183 InstalledAppResultLoader.class.getName()); 184 mAdapter.addSearchResults(new HashSet<>(dbResults), 185 DatabaseResultLoader.class.getName()); 186 mAdapter.notifyResultsLoaded(); 187 // Add subset of items 188 mAdapter.initializeSearch(""); 189 mAdapter.addSearchResults(new HashSet<>(appResults.subList(0, 1)), 190 InstalledAppResultLoader.class.getName()); 191 mAdapter.addSearchResults(new HashSet<>(dbResults.subList(0, 1)), 192 DatabaseResultLoader.class.getName()); 193 mAdapter.notifyResultsLoaded(); 194 195 List<SearchResult> results = mAdapter.getSearchResults(); 196 assertThat(results.get(0).title).isEqualTo(TITLES[0]); 197 assertThat(results.get(1).title).isEqualTo(TITLES[3]); 198 verify(mFragment, times(2)).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture()); 199 assertThat(mSearchResultsCountCaptor.getAllValues().toArray()) 200 .isEqualTo(new Integer[] {6, 2}); 201 } 202 @Test 203 public void testEndToEndSearch_smartSearchRankingEnabledAndSucceededAfterResultsLoaded() { 204 when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true); 205 206 List<SearchResult> appResults = getDummyAppResults(); 207 List<SearchResult> dbResults = getDummyDbResults(); 208 mAdapter.initializeSearch(""); 209 mAdapter.addSearchResults( 210 new HashSet<>(appResults), InstalledAppResultLoader.class.getName()); 211 mAdapter.addSearchResults( 212 new HashSet<>(dbResults), DatabaseResultLoader.class.getName()); 213 mAdapter.notifyResultsLoaded(); 214 mAdapter.onRankingScoresAvailable(getDummyRankingScores()); 215 216 List<SearchResult> results = mAdapter.getSearchResults(); 217 assertThat(results.get(0).title).isEqualTo(TITLES[2]); // charlie 218 assertThat(results.get(1).title).isEqualTo(TITLES[0]); // alpha 219 assertThat(results.get(2).title).isEqualTo(TITLES[1]); // bravo 220 assertThat(results.get(3).title).isEqualTo(TITLES[3]); // appAlpha 221 assertThat(results.get(4).title).isEqualTo(TITLES[4]); // appBravo 222 assertThat(results.get(5).title).isEqualTo(TITLES[5]); // appCharlie 223 verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture()); 224 assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6); 225 assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.SUCCEEDED); 226 } 227 228 @Test 229 public void testEndToEndSearch_smartSearchRankingEnabledAndSucceededBeforeResultsLoaded() { 230 when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true); 231 232 List<SearchResult> appResults = getDummyAppResults(); 233 List<SearchResult> dbResults = getDummyDbResults(); 234 mAdapter.initializeSearch(""); 235 mAdapter.onRankingScoresAvailable(getDummyRankingScores()); 236 mAdapter.addSearchResults( 237 new HashSet<>(appResults), InstalledAppResultLoader.class.getName()); 238 mAdapter.addSearchResults( 239 new HashSet<>(dbResults), DatabaseResultLoader.class.getName()); 240 mAdapter.notifyResultsLoaded(); 241 242 List<SearchResult> results = mAdapter.getSearchResults(); 243 assertThat(results.get(0).title).isEqualTo(TITLES[2]); // charlie 244 assertThat(results.get(1).title).isEqualTo(TITLES[0]); // alpha 245 assertThat(results.get(2).title).isEqualTo(TITLES[1]); // bravo 246 assertThat(results.get(3).title).isEqualTo(TITLES[3]); // appAlpha 247 assertThat(results.get(4).title).isEqualTo(TITLES[4]); // appBravo 248 assertThat(results.get(5).title).isEqualTo(TITLES[5]); // appCharlie 249 verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture()); 250 assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6); 251 assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.SUCCEEDED); 252 } 253 254 @Test 255 public void testEndToEndSearch_smartSearchRankingEnabledAndFailedAfterResultsLoaded() { 256 when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true); 257 258 List<SearchResult> appResults = getDummyAppResults(); 259 List<SearchResult> dbResults = getDummyDbResults(); 260 mAdapter.initializeSearch(""); 261 mAdapter.addSearchResults( 262 new HashSet<>(appResults), InstalledAppResultLoader.class.getName()); 263 mAdapter.addSearchResults( 264 new HashSet<>(dbResults), DatabaseResultLoader.class.getName()); 265 mAdapter.notifyResultsLoaded(); 266 mAdapter.onRankingFailed(); 267 268 List<SearchResult> results = mAdapter.getSearchResults(); 269 assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha 270 assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha 271 assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo 272 assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo 273 assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie 274 assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie 275 verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture()); 276 assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6); 277 assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.FAILED); 278 } 279 280 @Test 281 public void testEndToEndSearch_smartSearchRankingEnabledAndFailedBeforeResultsLoaded() { 282 when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true); 283 284 List<SearchResult> appResults = getDummyAppResults(); 285 List<SearchResult> dbResults = getDummyDbResults(); 286 mAdapter.initializeSearch(""); 287 mAdapter.onRankingFailed(); 288 mAdapter.addSearchResults( 289 new HashSet<>(appResults), InstalledAppResultLoader.class.getName()); 290 mAdapter.addSearchResults( 291 new HashSet<>(dbResults), DatabaseResultLoader.class.getName()); 292 mAdapter.notifyResultsLoaded(); 293 294 List<SearchResult> results = mAdapter.getSearchResults(); 295 assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha 296 assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha 297 assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo 298 assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo 299 assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie 300 assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie 301 verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture()); 302 assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6); 303 assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.FAILED); 304 } 305 306 @Test 307 public void testEndToEndSearch_smartSearchRankingEnabledAndTimedoutAfterResultsLoaded() { 308 when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true); 309 310 List<SearchResult> appResults = getDummyAppResults(); 311 List<SearchResult> dbResults = getDummyDbResults(); 312 mAdapter.initializeSearch(""); 313 mAdapter.addSearchResults( 314 new HashSet<>(appResults), InstalledAppResultLoader.class.getName()); 315 mAdapter.addSearchResults( 316 new HashSet<>(dbResults), DatabaseResultLoader.class.getName()); 317 mAdapter.notifyResultsLoaded(); 318 319 waitUntilRankingTimesOut(); 320 321 List<SearchResult> results = mAdapter.getSearchResults(); 322 assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha 323 assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha 324 assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo 325 assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo 326 assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie 327 assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie 328 verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture()); 329 assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6); 330 assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.TIMED_OUT); 331 } 332 333 @Test 334 public void testEndToEndSearch_smartSearchRankingEnabledAndTimedoutBeforeResultsLoaded() { 335 when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true); 336 337 List<SearchResult> appResults = getDummyAppResults(); 338 List<SearchResult> dbResults = getDummyDbResults(); 339 mAdapter.initializeSearch(""); 340 341 waitUntilRankingTimesOut(); 342 343 mAdapter.addSearchResults( 344 new HashSet<>(appResults), InstalledAppResultLoader.class.getName()); 345 mAdapter.addSearchResults( 346 new HashSet<>(dbResults), DatabaseResultLoader.class.getName()); 347 mAdapter.notifyResultsLoaded(); 348 349 List<SearchResult> results = mAdapter.getSearchResults(); 350 assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha 351 assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha 352 assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo 353 assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo 354 assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie 355 assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie 356 verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture()); 357 assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6); 358 assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.TIMED_OUT); 359 } 360 361 @Test 362 public void testDoSmartRanking_shouldRankAppResultsAfterDbResults() { 363 when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true); 364 365 List<SearchResult> appResults = getDummyAppResults(); 366 List<SearchResult> dbResults = getDummyDbResults(); 367 mAdapter.initializeSearch(""); 368 mAdapter.addSearchResults( 369 new HashSet<>(appResults), InstalledAppResultLoader.class.getName()); 370 mAdapter.addSearchResults( 371 new HashSet<>(dbResults), DatabaseResultLoader.class.getName()); 372 mAdapter.notifyResultsLoaded(); 373 mAdapter.onRankingScoresAvailable(getDummyRankingScores()); 374 List<SearchResult> results = mAdapter.doAsyncRanking(); 375 assertThat(results.get(0).title).isEqualTo(TITLES[2]); // charlie 376 assertThat(results.get(1).title).isEqualTo(TITLES[0]); // alpha 377 assertThat(results.get(2).title).isEqualTo(TITLES[1]); // bravo 378 assertThat(results.get(3).title).isEqualTo(TITLES[3]); // appAlpha 379 assertThat(results.get(4).title).isEqualTo(TITLES[4]); // appBravo 380 assertThat(results.get(5).title).isEqualTo(TITLES[5]); // appCharlie 381 } 382 383 @Test 384 public void testDoSmartRanking_shouldRankResultsWithMissingScoresAfterScoredResults() { 385 when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true); 386 387 List<SearchResult> appResults = getDummyAppResults(); 388 List<SearchResult> dbResults = getDummyDbResults(); 389 mAdapter.initializeSearch(""); 390 mAdapter.addSearchResults( 391 new HashSet<>(appResults), InstalledAppResultLoader.class.getName()); 392 mAdapter.addSearchResults( 393 new HashSet<>(dbResults), DatabaseResultLoader.class.getName()); 394 mAdapter.notifyResultsLoaded(); 395 List<Pair<String, Float>> rankingScores = getDummyRankingScores(); 396 rankingScores.remove(1); // no ranking score for alpha 397 mAdapter.onRankingScoresAvailable(rankingScores); 398 List<SearchResult> results = mAdapter.doAsyncRanking(); 399 assertThat(results.get(0).title).isEqualTo(TITLES[2]); // charlie 400 assertThat(results.get(1).title).isEqualTo(TITLES[1]); // bravo 401 assertThat(results.get(2).title).isEqualTo(TITLES[0]); // alpha 402 assertThat(results.get(3).title).isEqualTo(TITLES[3]); // appAlpha 403 assertThat(results.get(4).title).isEqualTo(TITLES[4]); // appBravo 404 assertThat(results.get(5).title).isEqualTo(TITLES[5]); // appCharlie 405 } 406 407 @Test 408 public void testGetUnsortedLoadedResults () { 409 List<SearchResult> appResults = getDummyAppResults(); 410 List<SearchResult> dbResults = getDummyDbResults(); 411 mAdapter.initializeSearch(""); 412 mAdapter.addSearchResults( 413 new HashSet<>(appResults), InstalledAppResultLoader.class.getName()); 414 mAdapter.addSearchResults( 415 new HashSet<>(dbResults), DatabaseResultLoader.class.getName()); 416 Set<CharSequence> expectedDbTitles = new HashSet<>( 417 Arrays.asList("alpha", "bravo", "charlie")); 418 Set<CharSequence> expectedAppTitles = new HashSet<>( 419 Arrays.asList("appAlpha", "appBravo", "appCharlie")); 420 Set<CharSequence> actualDbTitles = new HashSet<>(); 421 Set<CharSequence> actualAppTitles = new HashSet<>(); 422 for (SearchResult result : mAdapter.getUnsortedLoadedResults(SearchResultsAdapter 423 .DB_RESULTS_LOADER_KEY)) { 424 actualDbTitles.add(result.title); 425 } 426 for (SearchResult result : mAdapter.getUnsortedLoadedResults(SearchResultsAdapter 427 .APP_RESULTS_LOADER_KEY)) { 428 actualAppTitles.add(result.title); 429 } 430 assertThat(actualDbTitles).isEqualTo(expectedDbTitles); 431 assertThat(actualAppTitles).isEqualTo(expectedAppTitles); 432 } 433 434 @Test 435 public void testGetSortedLoadedResults() { 436 List<SearchResult> appResults = getDummyAppResults(); 437 List<SearchResult> dbResults = getDummyDbResults(); 438 mAdapter.initializeSearch(""); 439 mAdapter.addSearchResults( 440 new HashSet<>(appResults), InstalledAppResultLoader.class.getName()); 441 mAdapter.addSearchResults( 442 new HashSet<>(dbResults), DatabaseResultLoader.class.getName()); 443 List<? extends SearchResult> actualDbResults = 444 mAdapter.getSortedLoadedResults(SearchResultsAdapter.DB_RESULTS_LOADER_KEY); 445 List<? extends SearchResult> actualAppResults = 446 mAdapter.getSortedLoadedResults(SearchResultsAdapter.APP_RESULTS_LOADER_KEY); 447 assertThat(actualDbResults.get(0).title).isEqualTo(TITLES[0]); // charlie 448 assertThat(actualDbResults.get(1).title).isEqualTo(TITLES[1]); // bravo 449 assertThat(actualDbResults.get(2).title).isEqualTo(TITLES[2]); // alpha 450 assertThat(actualAppResults.get(0).title).isEqualTo(TITLES[3]); // appAlpha 451 assertThat(actualAppResults.get(1).title).isEqualTo(TITLES[4]); // appBravo 452 assertThat(actualAppResults.get(2).title).isEqualTo(TITLES[5]); // appCharlie 453 } 454 455 @Test 456 public void testInitializeSearch_shouldNotRunSmartRankingIfDisabled() { 457 when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(false); 458 mAdapter.initializeSearch(""); 459 mAdapter.notifyResultsLoaded(); 460 verify(mSearchFeatureProvider, never()).querySearchResults( 461 any(Context.class), anyString(), any(SearchResultsRankerCallback.class)); 462 assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.DISABLED); 463 } 464 465 @Test 466 public void testInitialSearch_shouldRunSmartRankingIfEnabled() { 467 when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true); 468 mAdapter.initializeSearch(""); 469 mAdapter.notifyResultsLoaded(); 470 verify(mSearchFeatureProvider, times(1)).querySearchResults( 471 any(Context.class), anyString(), any(SearchResultsRankerCallback.class)); 472 assertThat(mAdapter.getAsyncRankingState()) 473 .isEqualTo(SearchResultsAdapter.PENDING_RESULTS); 474 } 475 476 @Test 477 public void testGetRankingScoreByStableId() { 478 when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true); 479 480 List<SearchResult> appResults = getDummyAppResults(); 481 List<SearchResult> dbResults = getDummyDbResults(); 482 mAdapter.initializeSearch(""); 483 mAdapter.onRankingScoresAvailable(getDummyRankingScores()); 484 assertThat(mAdapter.getRankingScoreByStableId(dbResults.get(0).stableId)) 485 .isWithin(1e-10f).of(0.8f); 486 assertThat(mAdapter.getRankingScoreByStableId(dbResults.get(1).stableId)) 487 .isWithin(1e-10f).of(0.2f); 488 assertThat(mAdapter.getRankingScoreByStableId(dbResults.get(2).stableId)) 489 .isWithin(1e-10f).of(0.9f); 490 assertThat(mAdapter.getRankingScoreByStableId(appResults.get(0).stableId)) 491 .isEqualTo(-Float.MAX_VALUE); 492 assertThat(mAdapter.getRankingScoreByStableId(appResults.get(1).stableId)) 493 .isEqualTo(-Float.MAX_VALUE); 494 assertThat(mAdapter.getRankingScoreByStableId(appResults.get(2).stableId)) 495 .isEqualTo(-Float.MAX_VALUE); 496 } 497 498 private void waitUntilRankingTimesOut() { 499 while (mAdapter.getHandler().hasMessages(mAdapter.MSG_RANKING_TIMED_OUT)) { 500 try { 501 ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); 502 Thread.sleep(100); 503 } catch (InterruptedException e) { 504 // Do nothing 505 } 506 } 507 } 508 509 private List<SearchResult> getDummyDbResults() { 510 List<SearchResult> results = new ArrayList<>(); 511 ResultPayload payload = new ResultPayload(new Intent()); 512 SearchResult.Builder builder = new SearchResult.Builder(); 513 builder.setPayload(payload) 514 .setTitle(TITLES[0]) 515 .setRank(1) 516 .setStableId(Objects.hash(TITLES[0], "db")); 517 results.add(builder.build()); 518 519 builder.setTitle(TITLES[1]) 520 .setRank(3) 521 .setStableId(Objects.hash(TITLES[1], "db")); 522 results.add(builder.build()); 523 524 builder.setTitle(TITLES[2]) 525 .setRank(6) 526 .setStableId(Objects.hash(TITLES[2], "db")); 527 results.add(builder.build()); 528 529 return results; 530 } 531 532 private List<SearchResult> getDummyAppResults() { 533 List<SearchResult> results = new ArrayList<>(); 534 ResultPayload payload = new ResultPayload(new Intent()); 535 AppSearchResult.Builder builder = new AppSearchResult.Builder(); 536 builder.setPayload(payload) 537 .setTitle(TITLES[3]) 538 .setRank(1) 539 .setStableId(Objects.hash(TITLES[3], "app")); 540 results.add(builder.build()); 541 542 builder.setTitle(TITLES[4]) 543 .setRank(2) 544 .setStableId(Objects.hash(TITLES[4], "app")); 545 results.add(builder.build()); 546 547 builder.setTitle(TITLES[5]) 548 .setRank(4) 549 .setStableId(Objects.hash(TITLES[5], "app")); 550 results.add(builder.build()); 551 552 return results; 553 } 554 555 private Set<SearchResult> getIntentSampleResults() { 556 Set<SearchResult> sampleResults = new HashSet<>(); 557 ArrayList<String> breadcrumbs = new ArrayList<>(); 558 final Drawable icon = mContext.getDrawable(R.drawable.ic_search_24dp); 559 final ResultPayload payload = new ResultPayload(null); 560 final SearchResult.Builder builder = new Builder(); 561 builder.setTitle("title") 562 .setSummary("summary") 563 .setRank(1) 564 .addBreadcrumbs(breadcrumbs) 565 .setIcon(icon) 566 .setPayload(payload) 567 .setStableId(Objects.hash("title", "summary", 1)); 568 sampleResults.add(builder.build()); 569 570 builder.setRank(2) 571 .setStableId(Objects.hash("title", "summary", 2)); 572 sampleResults.add(builder.build()); 573 574 builder.setRank(3) 575 .setStableId(Objects.hash("title", "summary", 3)); 576 sampleResults.add(builder.build()); 577 return sampleResults; 578 } 579 580 private List<Pair<String, Float>> getDummyRankingScores() { 581 List<SearchResult> results = getDummyDbResults(); 582 List<Pair<String, Float>> scores = new ArrayList<>(); 583 scores.add(new Pair<>(Long.toString(results.get(2).stableId), 0.9f)); // charlie 584 scores.add(new Pair<>(Long.toString(results.get(0).stableId), 0.8f)); // alpha 585 scores.add(new Pair<>(Long.toString(results.get(1).stableId), 0.2f)); // bravo 586 return scores; 587 } 588} 589