diff --git a/tests/uitests/src/com/android/settings/search/SearchData.java b/tests/uitests/src/com/android/settings/search/SearchData.java deleted file mode 100644 index 201841bc292..00000000000 --- a/tests/uitests/src/com/android/settings/search/SearchData.java +++ /dev/null @@ -1,81 +0,0 @@ -package uitests.src.com.android.settings.search; - -import android.text.TextUtils; -import java.util.Objects; - - -/** - * Data class for {@link com.android.settings.search.SettingsSearchResultRegressionTest} - */ -public class SearchData { - public final String title; - public final String key; - - public String getTitle() { - return title; - } - - public String getKey() { - return key; - } - public static final String DELIM = ";"; - - public static SearchData from(String searchDataString) { - String[] split = searchDataString.trim().split(DELIM, -1); - - if (split.length != 2) { - throw new IllegalArgumentException("Arg is invalid: " + searchDataString); - } - - return new SearchData.Builder() - .setTitle(split[0]) - .setKey(split[1]) - .build(); - } - - @Override - public String toString() { - return title + DELIM + key; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof SearchData)) { - return false; - } - - SearchData other = (SearchData) obj; - return TextUtils.equals(this.title, other.title) - && TextUtils.equals(this.key, other.key); - } - - @Override - public int hashCode() { - return Objects.hash(title, key); - } - - private SearchData( - SearchData.Builder builder) { - this.title = builder.title; - this.key = builder.key; - } - - public static class Builder { - protected String title = ""; - protected String key = ""; - - public SearchData build() { - return new SearchData(this); - } - - public SearchData.Builder setTitle(String title) { - this.title = title; - return this; - } - - public SearchData.Builder setKey(String key) { - this.key = key; - return this; - } - } -} diff --git a/tests/uitests/src/com/android/settings/search/SettingsSearchResultRegressionTest.java b/tests/uitests/src/com/android/settings/search/SettingsSearchResultRegressionTest.java deleted file mode 100644 index 31900e436e8..00000000000 --- a/tests/uitests/src/com/android/settings/search/SettingsSearchResultRegressionTest.java +++ /dev/null @@ -1,210 +0,0 @@ - -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.android.settings.search; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import android.content.ContentResolver; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; - -import android.platform.test.annotations.Presubmit; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; -import android.text.TextUtils; - -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Set; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; -import uitests.src.com.android.settings.search.SearchData; - -@SmallTest -@RunWith(AndroidJUnit4.class) -public class SettingsSearchResultRegressionTest { - - private Context mContext; - - public interface IndexColumns { - String DATA_TITLE = "data_title"; - String DATA_KEY_REF = "data_key_reference"; - } - - private static final String ERROR_RESULTS_MISSING = - "\nSettings search results missing. \n" - + "If the changes are intentional, we want to update the master-list.\n"; - - private static final String ERROR_NEW_RESULTS = - "\nNew settings search results have been found.\nIf the changes are intentional, we want to" - + "prevent the new results from regressing.\n"; - - private static final String ERROR_RERUN_TEST = - "Please re-run the test \"generate_search_result_list\" by removing the '@Ignore' annotation above 'generate_search_result_list' test, and run: \n" - + "$ runtest --path packages/apps/Settings/tests/uitests/src/com/android/settings/search/SettingsSearchResultRegressionTest.java \n" - + "and copy the output into 'packages/apps/Settings/tests/uitests/assets/search_result_list'\n"; - - - @Before - public void setUp() { - mContext = InstrumentationRegistry.getContext(); - } - - /** - * Tests that the set of search results does not regress. - *

- * The data set used here (/tests/unit/assets/search_results_list) needs to be updated - * every once in a while so that we can check newly added results. - *

- */ - @Test - @Presubmit - public void searchResultsDoNotRegress() { - final ContentResolver resolver = mContext.getContentResolver(); - final Uri uri = getTestProviderUri(); - final Cursor cursor = resolver.query(uri, null, null, null, null); - - if (cursor == null) { - // Assume Settings Intelligence is wrong. - return; - } - - final Set availableSearchResults = getSearchDataFromCursor(cursor); - final Set registeredSearchResults = getRegisteredResults(); - - // Seed with results that we expect - final Set missingSearchResults = new HashSet<>(registeredSearchResults); - // Seed with results that are available - final Set newSearchResults = new HashSet<>(availableSearchResults); - - // Remove all available results, leaving results that have been removed. - missingSearchResults.removeAll(availableSearchResults); - // Remove all results we expect, leaving results that have not yet been registered. - newSearchResults.removeAll(registeredSearchResults); - - assertWithMessage(ERROR_RESULTS_MISSING + ERROR_RERUN_TEST) - .that(missingSearchResults).isEmpty(); - assertWithMessage(ERROR_NEW_RESULTS + ERROR_RERUN_TEST).that(newSearchResults).isEmpty(); - } - - // TODO (b/113907111) add a test to catch duplicate title search results. - - /** - * Test to generate a new list of search results. Uncomment the Test annotation and run the - * test to generate the list. - */ - @Ignore - @Test - public void generate_search_result_list() { - final ContentResolver resolver = mContext.getContentResolver(); - final Uri uri = getTestProviderUri(); - final Cursor cursor = resolver.query(uri, null, null, null, null); - final List availableSearchResults = - new ArrayList<>(getSearchDataFromCursor(cursor)); - - Collections.sort(availableSearchResults, Comparator.comparing(SearchData::getTitle) - .thenComparing(SearchData::getKey)); - - assertThat(generateListFromSearchData(availableSearchResults)).isNull(); - } - - private Set getSearchDataFromCursor(Cursor cursor) { - final Set searchData = new HashSet<>(); - - final int titleIndex = cursor.getColumnIndex( - IndexColumns.DATA_TITLE); - final int keyIndex = cursor.getColumnIndex( - IndexColumns.DATA_KEY_REF); - - while (cursor.moveToNext()) { - String title = cursor.getString(titleIndex); - String key = cursor.getString(keyIndex); - - if (TextUtils.isEmpty(title)) { - title = ""; - } - - if (TextUtils.isEmpty(key)) { - key = ""; - } - - searchData.add(new SearchData.Builder() - .setTitle(title) - .setKey(key) - .build()); - } - - return searchData; - } - - /** - * Utility method to generate the list of search results that this class uses to validate - * results. - */ - private String generateListFromSearchData(List searchData) { - StringBuilder builder = new StringBuilder(); - for (SearchData searchResult : searchData) { - builder.append(searchResult.title) - .append( - SearchData.DELIM) - .append(searchResult.key) - .append("\n"); - } - return builder.toString(); - } - - private Uri getTestProviderUri() { - return new Uri.Builder() - .scheme(ContentResolver.SCHEME_CONTENT) - .authority("com.google.android.settings.intelligence.modules.search.regression") - .build(); - } - - private Set getRegisteredResults() { - final String filename = "search_results_list"; - final Set registeredResults = new HashSet<>(); - - try { - final InputStream in = mContext.getAssets().open(filename); - BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - String line; - while ((line = reader.readLine()) != null) { - registeredResults.add( - SearchData.from(line)); - } - } catch (Exception e) { - throw new IllegalArgumentException("Error initializing registered result list " - + filename, e); - } - - return registeredResults; - } -} \ No newline at end of file diff --git a/tests/uitests/src/com/android/settings/ui/search/SearchData.java b/tests/uitests/src/com/android/settings/ui/search/SearchData.java new file mode 100644 index 00000000000..6a898bb7e10 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/search/SearchData.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui.search; + +import android.text.TextUtils; + +import java.util.Objects; + + +/** + * Data class for {@link SettingsSearchResultRegressionTest} + */ +public class SearchData { + public final String title; + public final String key; + + public String getTitle() { + return title; + } + + public String getKey() { + return key; + } + + public static final String DELIM = ";"; + + public static SearchData from(String searchDataString) { + String[] split = searchDataString.trim().split(DELIM, -1); + + if (split.length != 2) { + throw new IllegalArgumentException("Arg is invalid: " + searchDataString); + } + + return new SearchData.Builder() + .setTitle(split[0]) + .setKey(split[1]) + .build(); + } + + @Override + public String toString() { + return title + DELIM + key; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SearchData)) { + return false; + } + + SearchData other = (SearchData) obj; + return TextUtils.equals(this.title, other.title) + && TextUtils.equals(this.key, other.key); + } + + @Override + public int hashCode() { + return Objects.hash(title, key); + } + + private SearchData( + SearchData.Builder builder) { + this.title = builder.title; + this.key = builder.key; + } + + public static class Builder { + protected String title = ""; + protected String key = ""; + + public SearchData build() { + return new SearchData(this); + } + + public SearchData.Builder setTitle(String title) { + this.title = title; + return this; + } + + public SearchData.Builder setKey(String key) { + this.key = key; + return this; + } + } +} diff --git a/tests/uitests/src/com/android/settings/ui/search/SettingsSearchResultRegressionTest.java b/tests/uitests/src/com/android/settings/ui/search/SettingsSearchResultRegressionTest.java new file mode 100644 index 00000000000..73cfb3e4207 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/search/SettingsSearchResultRegressionTest.java @@ -0,0 +1,234 @@ + +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui.search; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.database.Cursor; +import android.net.Uri; +import android.platform.test.annotations.Presubmit; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.text.TextUtils; +import android.util.Log; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class SettingsSearchResultRegressionTest { + + private static final String TAG = "SearchRegressionTest"; + + private Context mContext; + + public interface IndexColumns { + String DATA_TITLE = "data_title"; + String DATA_KEY_REF = "data_key_reference"; + } + + private static final String ERROR_RESULTS_MISSING = + "\nSettings search results missing. \n" + + "If the changes are intentional, we want to update the master-list.\n"; + + private static final String ERROR_NEW_RESULTS = + "\nNew settings search results have been found.\nIf the changes are intentional, we " + + "want to" + + "prevent the new results from regressing.\n"; + + private static final String ERROR_RERUN_TEST = + "Please re-run the test \"generate_search_result_list\" by removing the '@Ignore' " + + "annotation above 'generate_search_result_list' test, and run: \n" + + "$ runtest --path " + + "packages/apps/Settings/tests/uitests/src/com/android/settings/search" + + "/SettingsSearchResultRegressionTest.java \n" + + "and copy the output into " + + "'packages/apps/Settings/tests/uitests/assets/search_result_list'\n"; + + + @Before + public void setUp() { + mContext = InstrumentationRegistry.getContext(); + } + + /** + * Tests that the set of search results does not regress. + *

+ * The data set used here (/tests/unit/assets/search_results_list) needs to be updated + * every once in a while so that we can check newly added results. + *

+ */ + @Test + @Presubmit + public void searchResultsDoNotRegress() { + final ContentResolver resolver = mContext.getContentResolver(); + final Uri uri = getTestProviderUri(); + if (uri == null) { + Log.e(TAG, "Something is wrong getting test provider uri, skipping"); + return; + } + final Cursor cursor = resolver.query(uri, null, null, null, null); + + if (cursor == null) { + // Assume Settings Intelligence is wrong. + return; + } + + final Set availableSearchResults = getSearchDataFromCursor(cursor); + final Set registeredSearchResults = getRegisteredResults(); + + // Seed with results that we expect + final Set missingSearchResults = new HashSet<>(registeredSearchResults); + // Seed with results that are available + final Set newSearchResults = new HashSet<>(availableSearchResults); + + // Remove all available results, leaving results that have been removed. + missingSearchResults.removeAll(availableSearchResults); + // Remove all results we expect, leaving results that have not yet been registered. + newSearchResults.removeAll(registeredSearchResults); + + assertWithMessage(ERROR_RESULTS_MISSING + ERROR_RERUN_TEST) + .that(missingSearchResults).isEmpty(); + assertWithMessage(ERROR_NEW_RESULTS + ERROR_RERUN_TEST).that(newSearchResults).isEmpty(); + } + + // TODO (b/113907111) add a test to catch duplicate title search results. + + /** + * Test to generate a new list of search results. Uncomment the Test annotation and run the + * test to generate the list. + */ + @Ignore + @Test + public void generate_search_result_list() { + final ContentResolver resolver = mContext.getContentResolver(); + final Uri uri = getTestProviderUri(); + if (uri == null) { + Log.e(TAG, "Something is wrong getting test provider uri, skipping"); + return; + } + final Cursor cursor = resolver.query(uri, null, null, null, null); + final List availableSearchResults = + new ArrayList<>(getSearchDataFromCursor(cursor)); + + Collections.sort(availableSearchResults, Comparator.comparing(SearchData::getTitle) + .thenComparing(SearchData::getKey)); + + assertThat(generateListFromSearchData(availableSearchResults)).isNull(); + } + + private Set getSearchDataFromCursor(Cursor cursor) { + final Set searchData = new HashSet<>(); + + final int titleIndex = cursor.getColumnIndex( + IndexColumns.DATA_TITLE); + final int keyIndex = cursor.getColumnIndex( + IndexColumns.DATA_KEY_REF); + + while (cursor.moveToNext()) { + String title = cursor.getString(titleIndex); + String key = cursor.getString(keyIndex); + + if (TextUtils.isEmpty(title)) { + title = ""; + } + + if (TextUtils.isEmpty(key)) { + key = ""; + } + + searchData.add(new SearchData.Builder() + .setTitle(title) + .setKey(key) + .build()); + } + + return searchData; + } + + /** + * Utility method to generate the list of search results that this class uses to validate + * results. + */ + private String generateListFromSearchData(List searchData) { + StringBuilder builder = new StringBuilder(); + for (SearchData searchResult : searchData) { + builder.append(searchResult.title) + .append( + SearchData.DELIM) + .append(searchResult.key) + .append("\n"); + } + return builder.toString(); + } + + private Uri getTestProviderUri() { + final Intent providerIntent = new Intent("com.android.settings.intelligence.DUMP_INDEX"); + + final List info = mContext.getPackageManager().queryIntentContentProviders( + providerIntent, 0 /* flags */); + if (info.size() != 1) { + Log.e(TAG, "Unexpected number of DUMP_INDEX providers, skipping. Expected 1, Found " + + info.size()); + return null; + } + return new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(info.get(0).providerInfo.authority) + .build(); + } + + private Set getRegisteredResults() { + final String filename = "search_results_list"; + final Set registeredResults = new HashSet<>(); + + try { + final InputStream in = mContext.getAssets().open(filename); + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String line; + while ((line = reader.readLine()) != null) { + registeredResults.add( + SearchData.from(line)); + } + } catch (Exception e) { + throw new IllegalArgumentException("Error initializing registered result list " + + filename, e); + } + + return registeredResults; + } +} \ No newline at end of file