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 package com.android.settings.search2; 18 19 import android.app.LoaderManager; 20 import android.content.Context; 21 import android.content.Loader; 22 import android.os.Bundle; 23 import android.view.View; 24 25 import com.android.internal.logging.nano.MetricsProto; 26 import com.android.settings.R; 27 import com.android.settings.SettingsRobolectricTestRunner; 28 import com.android.settings.TestConfig; 29 import com.android.settings.search.IndexingCallback; 30 import com.android.settings.testutils.FakeFeatureFactory; 31 32 import org.junit.Before; 33 import org.junit.Test; 34 import org.junit.runner.RunWith; 35 import org.mockito.Answers; 36 import org.mockito.Mock; 37 import org.mockito.MockitoAnnotations; 38 import org.robolectric.Robolectric; 39 import org.robolectric.RuntimeEnvironment; 40 import org.robolectric.annotation.Config; 41 import org.robolectric.util.ActivityController; 42 import org.robolectric.util.ReflectionHelpers; 43 44 import java.util.List; 45 46 import static com.google.common.truth.Truth.assertThat; 47 import static org.mockito.Matchers.any; 48 import static org.mockito.Matchers.anyString; 49 import static org.mockito.Matchers.eq; 50 import static org.mockito.Mockito.mock; 51 import static org.mockito.Mockito.never; 52 import static org.mockito.Mockito.spy; 53 import static org.mockito.Mockito.times; 54 import static org.mockito.Mockito.verify; 55 import static org.mockito.Mockito.when; 56 57 @RunWith(SettingsRobolectricTestRunner.class) 58 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) 59 public class SearchFragmentTest { 60 61 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 62 private Context mContext; 63 @Mock 64 private DatabaseResultLoader mDatabaseResultLoader; 65 @Mock 66 private InstalledAppResultLoader mInstalledAppResultLoader; 67 68 @Mock 69 private SavedQueryLoader mSavedQueryLoader; 70 @Mock 71 private SavedQueryController mSavedQueryController; 72 private FakeFeatureFactory mFeatureFactory; 73 74 @Before setUp()75 public void setUp() { 76 MockitoAnnotations.initMocks(this); 77 78 FakeFeatureFactory.setupForTest(mContext); 79 mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); 80 } 81 82 @Test screenRotate_shouldPersistQuery()83 public void screenRotate_shouldPersistQuery() { 84 when(mFeatureFactory.searchFeatureProvider 85 .getDatabaseSearchLoader(any(Context.class), anyString())) 86 .thenReturn(mDatabaseResultLoader); 87 when(mFeatureFactory.searchFeatureProvider 88 .getInstalledAppSearchLoader(any(Context.class), anyString())) 89 .thenReturn(mInstalledAppResultLoader); 90 when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) 91 .thenReturn(mSavedQueryLoader); 92 93 final Bundle bundle = new Bundle(); 94 final String testQuery = "test"; 95 ActivityController<SearchActivity> activityController = 96 Robolectric.buildActivity(SearchActivity.class); 97 activityController.setup(); 98 SearchFragment fragment = (SearchFragment) activityController.get().getFragmentManager() 99 .findFragmentById(R.id.main_content); 100 101 ReflectionHelpers.setField(fragment, "mShowingSavedQuery", false); 102 fragment.mQuery = testQuery; 103 104 activityController.saveInstanceState(bundle).pause().stop().destroy(); 105 106 activityController = Robolectric.buildActivity(SearchActivity.class); 107 activityController.setup(bundle); 108 109 assertThat(fragment.mQuery).isEqualTo(testQuery); 110 } 111 112 @Test screenRotateEmptyString_ShouldNotCrash()113 public void screenRotateEmptyString_ShouldNotCrash() { 114 when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) 115 .thenReturn(mSavedQueryLoader); 116 117 final Bundle bundle = new Bundle(); 118 ActivityController<SearchActivity> activityController = 119 Robolectric.buildActivity(SearchActivity.class); 120 activityController.setup(); 121 SearchFragment fragment = (SearchFragment) activityController.get().getFragmentManager() 122 .findFragmentById(R.id.main_content); 123 when(mFeatureFactory.searchFeatureProvider.isIndexingComplete(any(Context.class))) 124 .thenReturn(true); 125 126 fragment.mQuery = ""; 127 128 activityController.saveInstanceState(bundle).pause().stop().destroy(); 129 130 activityController = Robolectric.buildActivity(SearchActivity.class); 131 activityController.setup(bundle); 132 133 verify(mFeatureFactory.searchFeatureProvider, never()) 134 .getDatabaseSearchLoader(any(Context.class), anyString()); 135 verify(mFeatureFactory.searchFeatureProvider, never()) 136 .getInstalledAppSearchLoader(any(Context.class), anyString()); 137 } 138 139 @Test queryTextChange_shouldTriggerLoader()140 public void queryTextChange_shouldTriggerLoader() { 141 when(mFeatureFactory.searchFeatureProvider 142 .getDatabaseSearchLoader(any(Context.class), anyString())) 143 .thenReturn(mDatabaseResultLoader); 144 when(mFeatureFactory.searchFeatureProvider 145 .getInstalledAppSearchLoader(any(Context.class), anyString())) 146 .thenReturn(mInstalledAppResultLoader); 147 when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) 148 .thenReturn(mSavedQueryLoader); 149 150 final String testQuery = "test"; 151 ActivityController<SearchActivity> activityController = 152 Robolectric.buildActivity(SearchActivity.class); 153 activityController.setup(); 154 SearchFragment fragment = (SearchFragment) activityController.get().getFragmentManager() 155 .findFragmentById(R.id.main_content); 156 when(mFeatureFactory.searchFeatureProvider.isIndexingComplete(any(Context.class))) 157 .thenReturn(true); 158 159 fragment.onQueryTextChange(testQuery); 160 activityController.get().onBackPressed(); 161 162 activityController.pause().stop().destroy(); 163 164 verify(mFeatureFactory.metricsFeatureProvider, never()).action( 165 any(Context.class), 166 eq(MetricsProto.MetricsEvent.ACTION_LEAVE_SEARCH_RESULT_WITHOUT_QUERY)); 167 verify(mFeatureFactory.metricsFeatureProvider).histogram( 168 any(Context.class), eq(SearchFragment.RESULT_CLICK_COUNT), eq(0)); 169 verify(mFeatureFactory.searchFeatureProvider) 170 .getDatabaseSearchLoader(any(Context.class), anyString()); 171 verify(mFeatureFactory.searchFeatureProvider) 172 .getInstalledAppSearchLoader(any(Context.class), anyString()); 173 } 174 175 @Test queryTextChangeToEmpty_shouldLoadSavedQuery()176 public void queryTextChangeToEmpty_shouldLoadSavedQuery() { 177 when(mFeatureFactory.searchFeatureProvider 178 .getDatabaseSearchLoader(any(Context.class), anyString())) 179 .thenReturn(mDatabaseResultLoader); 180 when(mFeatureFactory.searchFeatureProvider 181 .getInstalledAppSearchLoader(any(Context.class), anyString())) 182 .thenReturn(mInstalledAppResultLoader); 183 when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) 184 .thenReturn(mSavedQueryLoader); 185 ActivityController<SearchActivity> activityController = 186 Robolectric.buildActivity(SearchActivity.class); 187 activityController.setup(); 188 SearchFragment fragment = spy((SearchFragment) activityController.get().getFragmentManager() 189 .findFragmentById(R.id.main_content)); 190 when(mFeatureFactory.searchFeatureProvider.isIndexingComplete(any(Context.class))) 191 .thenReturn(true); 192 ReflectionHelpers.setField(fragment, "mSavedQueryController", mSavedQueryController); 193 fragment.mQuery = "123"; 194 195 fragment.onQueryTextChange(""); 196 197 verify(mFeatureFactory.searchFeatureProvider, never()) 198 .getDatabaseSearchLoader(any(Context.class), anyString()); 199 verify(mFeatureFactory.searchFeatureProvider, never()) 200 .getInstalledAppSearchLoader(any(Context.class), anyString()); 201 verify(mSavedQueryController).loadSavedQueries(); 202 } 203 204 @Test updateIndex_TriggerOnCreate()205 public void updateIndex_TriggerOnCreate() { 206 when(mFeatureFactory.searchFeatureProvider 207 .getDatabaseSearchLoader(any(Context.class), anyString())) 208 .thenReturn(mDatabaseResultLoader); 209 when(mFeatureFactory.searchFeatureProvider 210 .getInstalledAppSearchLoader(any(Context.class), anyString())) 211 .thenReturn(mInstalledAppResultLoader); 212 when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) 213 .thenReturn(mSavedQueryLoader); 214 215 ActivityController<SearchActivity> activityController = 216 Robolectric.buildActivity(SearchActivity.class); 217 activityController.setup(); 218 SearchFragment fragment = (SearchFragment) activityController.get().getFragmentManager() 219 .findFragmentById(R.id.main_content); 220 when(mFeatureFactory.searchFeatureProvider.isIndexingComplete(any(Context.class))) 221 .thenReturn(true); 222 223 fragment.onAttach(null); 224 verify(mFeatureFactory.searchFeatureProvider).updateIndex(any(Context.class), 225 any(IndexingCallback.class)); 226 } 227 228 @Test syncLoaders_MergeWhenAllLoadersDone()229 public void syncLoaders_MergeWhenAllLoadersDone() { 230 when(mFeatureFactory.searchFeatureProvider 231 .getDatabaseSearchLoader(any(Context.class), anyString())) 232 .thenReturn(new MockDBLoader(RuntimeEnvironment.application)); 233 when(mFeatureFactory.searchFeatureProvider 234 .getInstalledAppSearchLoader(any(Context.class), anyString())) 235 .thenReturn(new MockAppLoader(RuntimeEnvironment.application)); 236 when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) 237 .thenReturn(mSavedQueryLoader); 238 239 ActivityController<SearchActivity> activityController = 240 Robolectric.buildActivity(SearchActivity.class); 241 activityController.setup(); 242 243 SearchFragment fragment = (SearchFragment) spy(activityController.get().getFragmentManager() 244 .findFragmentById(R.id.main_content)); 245 when(mFeatureFactory.searchFeatureProvider.isIndexingComplete(any(Context.class))) 246 .thenReturn(true); 247 248 fragment.onQueryTextChange("non-empty"); 249 250 Robolectric.flushForegroundThreadScheduler(); 251 252 verify(fragment, times(2)).onLoadFinished(any(Loader.class), any(List.class)); 253 } 254 255 @Test whenNoQuery_HideFeedbackIsCalled()256 public void whenNoQuery_HideFeedbackIsCalled() { 257 when(mFeatureFactory.searchFeatureProvider 258 .getDatabaseSearchLoader(any(Context.class), anyString())) 259 .thenReturn(new MockDBLoader(RuntimeEnvironment.application)); 260 when(mFeatureFactory.searchFeatureProvider 261 .getInstalledAppSearchLoader(any(Context.class), anyString())) 262 .thenReturn(new MockAppLoader(RuntimeEnvironment.application)); 263 when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) 264 .thenReturn(mSavedQueryLoader); 265 266 ActivityController<SearchActivity> activityController = 267 Robolectric.buildActivity(SearchActivity.class); 268 activityController.setup(); 269 SearchFragment fragment = (SearchFragment) spy(activityController.get().getFragmentManager() 270 .findFragmentById(R.id.main_content)); 271 when(mFeatureFactory.searchFeatureProvider.isIndexingComplete(any(Context.class))) 272 .thenReturn(true); 273 when(fragment.getLoaderManager()).thenReturn(mock(LoaderManager.class)); 274 275 fragment.onQueryTextChange(""); 276 Robolectric.flushForegroundThreadScheduler(); 277 278 verify(mFeatureFactory.searchFeatureProvider).hideFeedbackButton(); 279 } 280 281 @Test onLoadFinished_ShowsFeedback()282 public void onLoadFinished_ShowsFeedback() { 283 when(mFeatureFactory.searchFeatureProvider 284 .getDatabaseSearchLoader(any(Context.class), anyString())) 285 .thenReturn(new MockDBLoader(RuntimeEnvironment.application)); 286 when(mFeatureFactory.searchFeatureProvider 287 .getInstalledAppSearchLoader(any(Context.class), anyString())) 288 .thenReturn(new MockAppLoader(RuntimeEnvironment.application)); 289 when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) 290 .thenReturn(mSavedQueryLoader); 291 ActivityController<SearchActivity> activityController = 292 Robolectric.buildActivity(SearchActivity.class); 293 activityController.setup(); 294 SearchFragment fragment = (SearchFragment) activityController.get().getFragmentManager() 295 .findFragmentById(R.id.main_content); 296 when(mFeatureFactory.searchFeatureProvider.isIndexingComplete(any(Context.class))) 297 .thenReturn(true); 298 299 fragment.onQueryTextChange("non-empty"); 300 Robolectric.flushForegroundThreadScheduler(); 301 302 verify(mFeatureFactory.searchFeatureProvider).showFeedbackButton(any(SearchFragment.class), 303 any(View.class)); 304 } 305 306 @Test preIndexingFinished_isIndexingFinishedFlag_isFalse()307 public void preIndexingFinished_isIndexingFinishedFlag_isFalse() { 308 ActivityController<SearchActivity> activityController = 309 Robolectric.buildActivity(SearchActivity.class); 310 activityController.setup(); 311 SearchFragment fragment = (SearchFragment) activityController.get().getFragmentManager() 312 .findFragmentById(R.id.main_content); 313 314 when(mFeatureFactory.searchFeatureProvider.isIndexingComplete(any(Context.class))) 315 .thenReturn(false); 316 } 317 318 @Test onIndexingFinished_notShowingSavedQuery_initLoaders()319 public void onIndexingFinished_notShowingSavedQuery_initLoaders() { 320 ActivityController<SearchActivity> activityController = 321 Robolectric.buildActivity(SearchActivity.class); 322 activityController.setup(); 323 SearchFragment fragment = (SearchFragment) spy(activityController.get().getFragmentManager() 324 .findFragmentById(R.id.main_content)); 325 final LoaderManager loaderManager = mock(LoaderManager.class); 326 when(fragment.getLoaderManager()).thenReturn(loaderManager); 327 fragment.mShowingSavedQuery = false; 328 fragment.mQuery = null; 329 330 fragment.onIndexingFinished(); 331 332 verify(loaderManager).initLoader(eq(SearchFragment.LOADER_ID_DATABASE), 333 eq(null), any(LoaderManager.LoaderCallbacks.class)); 334 verify(loaderManager).initLoader(eq(SearchFragment.LOADER_ID_INSTALLED_APPS), 335 eq(null), any(LoaderManager.LoaderCallbacks.class)); 336 } 337 338 @Test onIndexingFinished_showingSavedQuery_loadsSavedQueries()339 public void onIndexingFinished_showingSavedQuery_loadsSavedQueries() { 340 ActivityController<SearchActivity> activityController = 341 Robolectric.buildActivity(SearchActivity.class); 342 activityController.setup(); 343 SearchFragment fragment = (SearchFragment) spy(activityController.get().getFragmentManager() 344 .findFragmentById(R.id.main_content)); 345 fragment.mShowingSavedQuery = true; 346 ReflectionHelpers.setField(fragment, "mSavedQueryController", mSavedQueryController); 347 348 fragment.onIndexingFinished(); 349 350 verify(fragment.mSavedQueryController).loadSavedQueries(); 351 } 352 353 @Test onIndexingFinished_noActivity_shouldNotCrash()354 public void onIndexingFinished_noActivity_shouldNotCrash() { 355 ActivityController<SearchActivity> activityController = 356 Robolectric.buildActivity(SearchActivity.class); 357 activityController.setup(); 358 SearchFragment fragment = (SearchFragment) spy(activityController.get().getFragmentManager() 359 .findFragmentById(R.id.main_content)); 360 when(mFeatureFactory.searchFeatureProvider.isIndexingComplete(any(Context.class))) 361 .thenReturn(true); 362 fragment.mQuery = "bright"; 363 ReflectionHelpers.setField(fragment, "mLoaderManager", null); 364 ReflectionHelpers.setField(fragment, "mHost", null); 365 366 fragment.onIndexingFinished(); 367 // no crash 368 } 369 } 370