From 6efea1e624bb4b48290000cfdb82df224a31b81d Mon Sep 17 00:00:00 2001 From: Matthew Fritze Date: Fri, 12 May 2017 15:59:19 -0700 Subject: [PATCH] Update Settings search result unique ids - SearchResult stableIds are now DocIds from the database - DocIds are data reference key's hash, when the key is not empty or null - Otherwise, DocIds are a hashcode from a set of fields. Change-Id: Id36f7bf4ceaaa3a2bd326ecafbfe97fd0b247df2 Fixes: 37327194 Test: make RunSettingsRoboTest --- .../search/CursorToSearchResultConverter.java | 55 ++-- .../search/DatabaseIndexingManager.java | 9 +- .../settings/search/DatabaseResultLoader.java | 96 ++----- .../search/InstalledAppResultLoader.java | 7 +- .../settings/search/SavedQueryLoader.java | 5 +- .../android/settings/search/SearchResult.java | 36 ++- .../CursorToSearchResultConverterTest.java | 179 ++++++------ .../search/DatabaseResultLoaderTest.java | 262 +++++------------- .../search/InlineSwitchViewHolderTest.java | 13 +- .../search/IntentSearchViewHolderTest.java | 38 +-- .../search/SearchResultBuilderTest.java | 92 +++--- .../search/SearchResultsAdapterTest.java | 54 ++-- 12 files changed, 347 insertions(+), 499 deletions(-) diff --git a/src/com/android/settings/search/CursorToSearchResultConverter.java b/src/com/android/settings/search/CursorToSearchResultConverter.java index 1fa3980c84b..1a0f8560fe9 100644 --- a/src/com/android/settings/search/CursorToSearchResultConverter.java +++ b/src/com/android/settings/search/CursorToSearchResultConverter.java @@ -28,9 +28,7 @@ import android.util.Log; import com.android.settings.dashboard.SiteMapManager; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -64,12 +62,8 @@ class CursorToSearchResultConverter { private final String TAG = "CursorConverter"; - private final String mQueryText; - private final Context mContext; - private final Set mKeys; - private final int LONG_TITLE_LENGTH = 20; private static final String[] whiteList = { @@ -87,19 +81,17 @@ class CursorToSearchResultConverter { private static final Set prioritySettings = new HashSet(Arrays.asList(whiteList)); - public CursorToSearchResultConverter(Context context, String queryText) { + public CursorToSearchResultConverter(Context context) { mContext = context; - mKeys = new HashSet<>(); - mQueryText = queryText; } - public List convertCursor(SiteMapManager sitemapManager, + public Set convertCursor(SiteMapManager sitemapManager, Cursor cursorResults, int baseRank) { if (cursorResults == null) { return null; } final Map contextMap = new HashMap<>(); - final List results = new ArrayList<>(); + final Set results = new HashSet<>(); while (cursorResults.moveToNext()) { SearchResult result = buildSingleSearchResultFromCursor(sitemapManager, @@ -108,22 +100,12 @@ class CursorToSearchResultConverter { results.add(result); } } - Collections.sort(results); return results; } private SearchResult buildSingleSearchResultFromCursor(SiteMapManager sitemapManager, Map contextMap, Cursor cursor, int baseRank) { - final String docId = cursor.getString(COLUMN_INDEX_ID); - /* Make sure that this result has not yet been added as a result. Checking the docID - covers the case of multiple queries matching the same row, but we need to also to check - for potentially the same named or slightly varied names pointing to the same page. - */ - if (mKeys.contains(docId)) { - return null; - } - mKeys.add(docId); - + final int docId = cursor.getInt(COLUMN_INDEX_ID); final String pkgName = cursor.getString(COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE); final String title = cursor.getString(COLUMN_INDEX_TITLE); final String summaryOn = cursor.getString(COLUMN_INDEX_SUMMARY_ON); @@ -135,15 +117,16 @@ class CursorToSearchResultConverter { final ResultPayload payload = getUnmarshalledPayload(marshalledPayload, payloadType); final List breadcrumbs = getBreadcrumbs(sitemapManager, cursor); - final int rank = getRank(title, breadcrumbs, baseRank, key); + final int rank = getRank(title, baseRank, key); - final SearchResult.Builder builder = new SearchResult.Builder(); - builder.addTitle(title) - .addSummary(summaryOn) + final SearchResult.Builder builder = new SearchResult.Builder() + .setStableId(docId) + .setTitle(title) + .setSummary(summaryOn) .addBreadcrumbs(breadcrumbs) - .addRank(rank) - .addIcon(getIconForPackage(contextMap, pkgName, className, iconResStr)) - .addPayload(payload); + .setRank(rank) + .setIcon(getIconForPackage(contextMap, pkgName, className, iconResStr)) + .setPayload(payload); return builder.build(); } @@ -206,27 +189,23 @@ class CursorToSearchResultConverter { * There are three checks * A) If the result is prioritized and the highest base level * B) If the query matches the highest level menu title - * C) If the query matches a subsequent menu title - * D) Is the title longer than 20 + * C) If the query is longer than 20 * * If the query matches A, set it to TOP_RANK - * If the query matches B and C, the offset is 0. - * If the query matches C only, the offset is 1. - * If the query matches neither B nor C, the offset is 2. - * If the query matches D, the offset is 2 + * If the query matches B, the offset is 0. + * If the query matches C, the offset is 1 * @param title of the result. - * @param crumbs from the Information Architecture * @param baseRank of the result. Lower if it's a better result. * @return */ - private int getRank(String title, List crumbs, int baseRank, String key) { + private int getRank(String title, int baseRank, String key) { // The result can only be prioritized if it is a top ranked result. if (prioritySettings.contains(key) && baseRank < BASE_RANKS[1]) { return TOP_RANK; } if (title.length() > LONG_TITLE_LENGTH) { - return baseRank + 2; + return baseRank + 1; } return baseRank; } diff --git a/src/com/android/settings/search/DatabaseIndexingManager.java b/src/com/android/settings/search/DatabaseIndexingManager.java index 0e107747a3f..746ab8a399f 100644 --- a/src/com/android/settings/search/DatabaseIndexingManager.java +++ b/src/com/android/settings/search/DatabaseIndexingManager.java @@ -1061,10 +1061,11 @@ public class DatabaseIndexingManager { * Returns the doc id for this row. */ public int getDocId() { - // The DocID should contains more than the title string itself (you may have two - // settings with the same title). So we need to use a combination of multiple - // attributes from this row. - return Objects.hash(updatedTitle, screenTitle, key, payloadType); + // Eventually we want all DocIds to be the data_reference key. For settings values, + // this will be preference keys, and for non-settings they should be unique. + return TextUtils.isEmpty(key) + ? Objects.hash(updatedTitle, className, screenTitle, intentTargetClass) + : key.hashCode(); } public static class Builder { diff --git a/src/com/android/settings/search/DatabaseResultLoader.java b/src/com/android/settings/search/DatabaseResultLoader.java index 853e69142a2..03f5cb43a43 100644 --- a/src/com/android/settings/search/DatabaseResultLoader.java +++ b/src/com/android/settings/search/DatabaseResultLoader.java @@ -21,13 +21,15 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; -import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import com.android.settings.dashboard.SiteMapManager; import com.android.settings.utils.AsyncLoader; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import static com.android.settings.search.IndexDatabaseHelper.IndexColumns; import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX; @@ -108,7 +110,7 @@ public class DatabaseResultLoader extends AsyncLoader primaryFirstWordResults; - final List primaryMidWordResults; - final List secondaryResults; - final List tertiaryResults; + final Set resultSet = new HashSet<>(); - primaryFirstWordResults = firstWordQuery(MATCH_COLUMNS_PRIMARY, BASE_RANKS[0]); - primaryMidWordResults = secondaryWordQuery(MATCH_COLUMNS_PRIMARY, BASE_RANKS[1]); - secondaryResults = anyWordQuery(MATCH_COLUMNS_SECONDARY, BASE_RANKS[2]); - tertiaryResults = anyWordQuery(MATCH_COLUMNS_TERTIARY, BASE_RANKS[3]); + resultSet.addAll(firstWordQuery(MATCH_COLUMNS_PRIMARY, BASE_RANKS[0])); + resultSet.addAll(secondaryWordQuery(MATCH_COLUMNS_PRIMARY, BASE_RANKS[1])); + resultSet.addAll(anyWordQuery(MATCH_COLUMNS_SECONDARY, BASE_RANKS[2])); + resultSet.addAll(anyWordQuery(MATCH_COLUMNS_TERTIARY, BASE_RANKS[3])); - final List results = new ArrayList<>( - primaryFirstWordResults.size() - + primaryMidWordResults.size() - + secondaryResults.size() - + tertiaryResults.size()); - - results.addAll(primaryFirstWordResults); - results.addAll(primaryMidWordResults); - results.addAll(secondaryResults); - results.addAll(tertiaryResults); - - return removeDuplicates(results); + final List results = new ArrayList<>(resultSet); + Collections.sort(results); + return results; } @Override @@ -171,7 +161,7 @@ public class DatabaseResultLoader extends AsyncLoader firstWordQuery(String[] matchColumns, int baseRank) { + private Set firstWordQuery(String[] matchColumns, int baseRank) { final String whereClause = buildSingleWordWhereClause(matchColumns); final String query = mQueryText + "%"; final String[] selection = buildSingleWordSelection(query, matchColumns.length); @@ -187,7 +177,7 @@ public class DatabaseResultLoader extends AsyncLoader secondaryWordQuery(String[] matchColumns, int baseRank) { + private Set secondaryWordQuery(String[] matchColumns, int baseRank) { final String whereClause = buildSingleWordWhereClause(matchColumns); final String query = "% " + mQueryText + "%"; final String[] selection = buildSingleWordSelection(query, matchColumns.length); @@ -202,7 +192,7 @@ public class DatabaseResultLoader extends AsyncLoader anyWordQuery(String[] matchColumns, int baseRank) { + private Set anyWordQuery(String[] matchColumns, int baseRank) { final String whereClause = buildTwoWordWhereClause(matchColumns); final String[] selection = buildAnyWordSelection(matchColumns.length * 2); @@ -217,9 +207,8 @@ public class DatabaseResultLoader extends AsyncLoader query(String whereClause, String[] selection, int baseRank) { - final SQLiteDatabase database = IndexDatabaseHelper.getInstance(mContext) - .getReadableDatabase(); + private Set query(String whereClause, String[] selection, int baseRank) { + SQLiteDatabase database = IndexDatabaseHelper.getInstance(mContext).getReadableDatabase(); final Cursor resultCursor = database.query(TABLE_PREFS_INDEX, SELECT_COLUMNS, whereClause, selection, null, null, null); return mConverter.convertCursor(mSiteMapManager, resultCursor, baseRank); @@ -299,55 +288,4 @@ public class DatabaseResultLoader extends AsyncLoader removeDuplicates(List results) { - SearchResult primaryResult, secondaryResult; - - // We accept the O(n^2) solution because the number of results is small. - for (int i = results.size() - 1; i >= 0; i--) { - secondaryResult = results.get(i); - - for (int j = i - 1; j >= 0; j--) { - primaryResult = results.get(j); - if (areDuplicateResults(primaryResult, secondaryResult)) { - - if (primaryResult.viewType != ResultPayload.PayloadType.INTENT) { - // Case where both payloads are inline - results.remove(i); - break; - } else if (secondaryResult.viewType != ResultPayload.PayloadType.INTENT) { - // Case where only second result is inline - results.remove(j); - i--; // shift the top index to reflect the lower element being removed - } else { - // Case where both payloads are intent - results.remove(i); - } - } - } - } - return results; - } - - /** - * @return True when the two {@link SearchResult SearchResults} have the same title, and the same - * non-empty summary. - */ - private boolean areDuplicateResults(SearchResult primary, SearchResult secondary) { - return TextUtils.equals(primary.title, secondary.title) - && TextUtils.equals(primary.summary, secondary.summary) - && !TextUtils.isEmpty(primary.summary); - } } \ No newline at end of file diff --git a/src/com/android/settings/search/InstalledAppResultLoader.java b/src/com/android/settings/search/InstalledAppResultLoader.java index 29668383a58..76f3a00240f 100644 --- a/src/com/android/settings/search/InstalledAppResultLoader.java +++ b/src/com/android/settings/search/InstalledAppResultLoader.java @@ -95,10 +95,11 @@ public class InstalledAppResultLoader extends AsyncLoader> final SavedQueryPayload payload = new SavedQueryPayload( cursor.getString(cursor.getColumnIndex(SavedQueriesColumns.QUERY))); results.add(new SearchResult.Builder() - .addTitle(payload.query) - .addPayload(payload) + .setStableId(payload.hashCode()) + .setTitle(payload.query) + .setPayload(payload) .build()); } return results; diff --git a/src/com/android/settings/search/SearchResult.java b/src/com/android/settings/search/SearchResult.java index c0e817c3c5c..d96661a38c9 100644 --- a/src/com/android/settings/search/SearchResult.java +++ b/src/com/android/settings/search/SearchResult.java @@ -18,15 +18,18 @@ package com.android.settings.search; import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.util.Log; import java.util.List; -import java.util.Objects; /** * Data class as an interface for all Search Results. */ public class SearchResult implements Comparable { + private static final String TAG = "SearchResult"; + /** * Defines the lowest rank for a search result to be considered as ranked. Results with ranks * higher than this have no guarantee for sorting order. @@ -84,9 +87,10 @@ public class SearchResult implements Comparable { /** * Stable id for this object. */ - public final long stableId; + public final int stableId; protected SearchResult(Builder builder) { + stableId = builder.mStableId; title = builder.mTitle; summary = builder.mSummary; breadcrumbs = builder.mBreadcrumbs; @@ -94,7 +98,6 @@ public class SearchResult implements Comparable { icon = builder.mIcon; payload = builder.mResultPayload; viewType = payload.getType(); - stableId = Objects.hash(title, summary, breadcrumbs, rank, viewType); } @Override @@ -118,7 +121,7 @@ public class SearchResult implements Comparable { @Override public int hashCode() { - return (int) stableId; + return stableId; } public static class Builder { @@ -128,13 +131,14 @@ public class SearchResult implements Comparable { protected int mRank = 42; protected ResultPayload mResultPayload; protected Drawable mIcon; + protected int mStableId; - public Builder addTitle(CharSequence title) { + public Builder setTitle(CharSequence title) { mTitle = title; return this; } - public Builder addSummary(CharSequence summary) { + public Builder setSummary(CharSequence summary) { mSummary = summary; return this; } @@ -144,29 +148,37 @@ public class SearchResult implements Comparable { return this; } - public Builder addRank(int rank) { + public Builder setRank(int rank) { if (rank >= 0 && rank <= 9) { mRank = rank; } return this; } - public Builder addIcon(Drawable icon) { + public Builder setIcon(Drawable icon) { mIcon = icon; return this; } - public Builder addPayload(ResultPayload payload) { + public Builder setPayload(ResultPayload payload) { mResultPayload = payload; return this; } + public Builder setStableId(int stableId) { + mStableId = stableId; + return this; + } + public SearchResult build() { // Check that all of the mandatory fields are set. - if (mTitle == null) { - throw new IllegalArgumentException("SearchResult missing title argument"); + if (TextUtils.isEmpty(mTitle)) { + throw new IllegalStateException("SearchResult missing title argument"); + } else if (mStableId == 0) { + Log.v(TAG, "No stable ID on SearchResult with title: " + mTitle); + throw new IllegalStateException("SearchResult missing stableId argument"); } else if (mResultPayload == null) { - throw new IllegalArgumentException("SearchResult missing Payload argument"); + throw new IllegalStateException("SearchResult missing Payload argument"); } return new SearchResult(this); } diff --git a/tests/robotests/src/com/android/settings/search/CursorToSearchResultConverterTest.java b/tests/robotests/src/com/android/settings/search/CursorToSearchResultConverterTest.java index b43846db01f..514d598bd64 100644 --- a/tests/robotests/src/com/android/settings/search/CursorToSearchResultConverterTest.java +++ b/tests/robotests/src/com/android/settings/search/CursorToSearchResultConverterTest.java @@ -50,7 +50,9 @@ import org.robolectric.Robolectric; import org.robolectric.annotation.Config; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Set; import static com.google.common.truth.Truth.assertThat; @@ -58,17 +60,14 @@ import static com.google.common.truth.Truth.assertThat; @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class CursorToSearchResultConverterTest { - private static final String ID = "id"; - private static final String[] TITLES = {"title1", "title2", "title3"}; + private static final List TITLES = Arrays.asList("title1", "title2", "title3"); private static final String SUMMARY = "summary"; private static final String TARGET_PACKAGE = "a.b.c"; private static final String TARGET_CLASS = "a.b.c.class"; - private static final String QUERY = "query"; private static final String KEY = "key"; private static final Intent INTENT = new Intent("com.android.settings"); private static final int ICON = R.drawable.ic_search_history; private static final int BASE_RANK = 1; - private static final int EXAMPLES = 3; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private SiteMapManager mSiteMapManager; @@ -80,46 +79,47 @@ public class CursorToSearchResultConverterTest { MockitoAnnotations.initMocks(this); Context context = Robolectric.buildActivity(Activity.class).get(); mDrawable = context.getDrawable(ICON); - mConverter = new CursorToSearchResultConverter(context, QUERY); + mConverter = new CursorToSearchResultConverter(context); } @Test public void testParseNullResults_ReturnsNull() { - final List results = mConverter.convertCursor(mSiteMapManager, null, BASE_RANK); + final Set results = mConverter.convertCursor( + mSiteMapManager, null, BASE_RANK); assertThat(results).isNull(); } @Test public void testParseCursor_NotNull() { - final List results = mConverter.convertCursor( + final Set results = mConverter.convertCursor( mSiteMapManager, getDummyCursor(), BASE_RANK); assertThat(results).isNotNull(); } @Test public void testParseCursor_MatchesRank() { - final List results = mConverter.convertCursor( + final Set results = mConverter.convertCursor( mSiteMapManager, getDummyCursor(), BASE_RANK); - for (int i = 0; i < EXAMPLES; i++) { - assertThat(results.get(i).rank).isEqualTo(BASE_RANK); + for (SearchResult result : results) { + assertThat(result.rank).isEqualTo(BASE_RANK); } } @Test public void testParseCursor_MatchesTitle() { - final List results = mConverter.convertCursor( + final Set results = mConverter.convertCursor( mSiteMapManager, getDummyCursor(), BASE_RANK); - for (int i = 0; i < EXAMPLES; i++) { - assertThat(results.get(i).title).isEqualTo(TITLES[i]); + for (SearchResult result : results) { + assertThat(TITLES).contains(result.title); } } @Test public void testParseCursor_MatchesSummary() { - final List results = mConverter.convertCursor( + final Set results = mConverter.convertCursor( mSiteMapManager, getDummyCursor(), BASE_RANK); - for (int i = 0; i < EXAMPLES; i++) { - assertThat(results.get(i).summary).isEqualTo(SUMMARY); + for (SearchResult result : results) { + assertThat(result.summary).isEqualTo(SUMMARY); } } @@ -129,7 +129,7 @@ public class CursorToSearchResultConverterTest { final byte[] payload = ResultPayloadUtils.marshall(new ResultPayload(INTENT)); final String BLANK = ""; cursor.addRow(new Object[]{ - ID, // Doc ID + KEY.hashCode(), // Doc ID "Longer than 20 characters", // Title SUMMARY, // Summary on SUMMARY, // summary off @@ -139,37 +139,37 @@ public class CursorToSearchResultConverterTest { BLANK, // action null, // target package BLANK, // target class - BLANK, // Key + KEY, // Key PayloadType.INTENT, // Payload Type payload // Payload }); - final List results = mConverter.convertCursor( + final Set results = mConverter.convertCursor( mSiteMapManager, cursor, BASE_RANK); - Drawable resultDrawable = results.get(0).icon; - assertThat(resultDrawable).isNotNull(); - assertThat(resultDrawable.toString()).isEqualTo(mDrawable.toString()); + for (SearchResult result : results) { + Drawable resultDrawable = result.icon; + assertThat(resultDrawable).isNotNull(); + assertThat(resultDrawable.toString()).isEqualTo(mDrawable.toString()); + } } @Test public void testParseCursor_NoIcon() { - final List results = mConverter.convertCursor( - mSiteMapManager, getDummyCursor(false /* hasIcon */, "" /* className */, - "" /* key */), BASE_RANK); - for (int i = 0; i < EXAMPLES; i++) { - Drawable resultDrawable = results.get(i).icon; - assertThat(resultDrawable).isNull(); + final Set results = mConverter.convertCursor( + mSiteMapManager, getDummyCursor("noIcon" /* key */, "" /* className */), BASE_RANK); + for (SearchResult result : results) { + assertThat(result.icon).isNull(); } } @Test public void testParseCursor_MatchesPayloadType() { - final List results = mConverter.convertCursor( + final Set results = mConverter.convertCursor( mSiteMapManager, getDummyCursor(), BASE_RANK); ResultPayload payload; - for (int i = 0; i < EXAMPLES; i++) { - payload = results.get(i).payload; + for (SearchResult result : results) { + payload = result.payload; assertThat(payload.getType()).isEqualTo(PayloadType.INTENT); } } @@ -180,7 +180,7 @@ public class CursorToSearchResultConverterTest { final byte[] payload = ResultPayloadUtils.marshall(new ResultPayload(INTENT)); final String BLANK = ""; cursor.addRow(new Object[]{ - ID, // Doc ID + KEY.hashCode(), // Doc ID "Longer than 20 characters", // Title SUMMARY, // Summary on SUMMARY, // summary off @@ -190,22 +190,24 @@ public class CursorToSearchResultConverterTest { BLANK, // action null, // target package BLANK, // target class - BLANK, // Key + KEY, // Key PayloadType.INTENT, // Payload Type payload // Payload }); - final List results = mConverter.convertCursor(mSiteMapManager, cursor, + final Set results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); - assertThat(results.get(0).rank).isEqualTo(BASE_RANK + 2); + for (SearchResult result : results) { + assertThat(result.rank).isEqualTo(BASE_RANK + 1); + } } @Test public void testParseCursor_MatchesResultPayload() { - final List results = mConverter.convertCursor( + final Set results = mConverter.convertCursor( mSiteMapManager, getDummyCursor(), BASE_RANK); ResultPayload payload; - for (int i = 0; i < EXAMPLES; i++) { - payload = results.get(i).payload; + for (SearchResult result : results) { + payload = result.payload; Intent intent = payload.getIntent(); assertThat(intent.getAction()).isEqualTo(INTENT.getAction()); } @@ -229,8 +231,8 @@ public class CursorToSearchResultConverterTest { final InlineSwitchPayload payload = new InlineSwitchPayload(uri, source, map, intent); cursor.addRow(new Object[]{ - ID, // Doc ID - TITLES[0], // Title + KEY.hashCode(), // Doc ID + TITLES.get(0), // Title SUMMARY, // Summary on SUMMARY, // summary off SwipeToNotificationSettings.class.getName(), @@ -239,20 +241,23 @@ public class CursorToSearchResultConverterTest { BLANK, // action null, // target package BLANK, // target class - BLANK, // Key + KEY, // Key type, // Payload Type ResultPayloadUtils.marshall(payload) // Payload }); - final List results = mConverter.convertCursor(mSiteMapManager, cursor, + final Set results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); - final InlineSwitchPayload newPayload = (InlineSwitchPayload) results.get(0).payload; - final Intent rebuiltIntent = newPayload.getIntent(); - assertThat(newPayload.settingsUri).isEqualTo(uri); - assertThat(newPayload.inlineType).isEqualTo(type); - assertThat(newPayload.settingSource).isEqualTo(source); - assertThat(newPayload.valueMap.get(1)).isTrue(); - assertThat(newPayload.valueMap.get(0)).isFalse(); - assertThat(rebuiltIntent.getStringExtra(intentKey)).isEqualTo(intentVal); + + for (SearchResult result : results) { + final InlineSwitchPayload newPayload = (InlineSwitchPayload) result.payload; + final Intent rebuiltIntent = newPayload.getIntent(); + assertThat(newPayload.settingsUri).isEqualTo(uri); + assertThat(newPayload.inlineType).isEqualTo(type); + assertThat(newPayload.settingSource).isEqualTo(source); + assertThat(newPayload.valueMap.get(1)).isTrue(); + assertThat(newPayload.valueMap.get(0)).isFalse(); + assertThat(rebuiltIntent.getStringExtra(intentKey)).isEqualTo(intentVal); + } } // The following tests are temporary, and should be removed when we replace the Search @@ -262,119 +267,137 @@ public class CursorToSearchResultConverterTest { public void testWifiKey_PrioritizedResult() { final String key = "main_toggle_wifi"; final Cursor cursor = getDummyCursor(key, WifiSettings.class.getName()); - final List results = mConverter.convertCursor(mSiteMapManager, cursor, + final Set results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); - assertThat(results.get(0).rank).isEqualTo(SearchResult.TOP_RANK); + for (SearchResult result : results) { + assertThat(result.rank).isEqualTo(SearchResult.TOP_RANK); + } } @Test public void testBluetoothKey_PrioritizedResult() { final String key = "main_toggle_bluetooth"; final Cursor cursor = getDummyCursor(key, WifiSettings.class.getName()); - final List results = mConverter.convertCursor(mSiteMapManager, cursor, + final Set results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); - assertThat(results.get(0).rank).isEqualTo(SearchResult.TOP_RANK); + for (SearchResult result : results) { + assertThat(result.rank).isEqualTo(SearchResult.TOP_RANK); + } } @Test public void testAirplaneKey_PrioritizedResult() { final String key = "toggle_airplane"; final Cursor cursor = getDummyCursor(key, WifiSettings.class.getName()); - List results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); - - assertThat(results.get(0).rank).isEqualTo(SearchResult.TOP_RANK); + Set results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); + for (SearchResult result : results) { + assertThat(result.rank).isEqualTo(SearchResult.TOP_RANK); + } } @Test public void testHotspotKey_PrioritizedResult() { final String key = "tether_settings"; final Cursor cursor = getDummyCursor(key, WifiSettings.class.getName()); - final List results = mConverter.convertCursor(mSiteMapManager, cursor, + final Set results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); - assertThat(results.get(0).rank).isEqualTo(SearchResult.TOP_RANK); + for (SearchResult result : results) { + assertThat(result.rank).isEqualTo(SearchResult.TOP_RANK); + } } @Test public void testBatterySaverKey_PrioritizedResult() { final String key = "battery_saver"; final Cursor cursor = getDummyCursor(key, WifiSettings.class.getName()); - final List results = mConverter.convertCursor(mSiteMapManager, cursor, + final Set results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); - assertThat(results.get(0).rank).isEqualTo(SearchResult.TOP_RANK); + for (SearchResult result : results) { + assertThat(result.rank).isEqualTo(SearchResult.TOP_RANK); + } } @Test public void testNFCKey_PrioritizedResult() { final String key = "toggle_nfc"; final Cursor cursor = getDummyCursor(key, WifiSettings.class.getName()); - final List results = mConverter.convertCursor(mSiteMapManager, cursor, + final Set results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); - assertThat(results.get(0).rank).isEqualTo(SearchResult.TOP_RANK); + for (SearchResult result : results) { + assertThat(result.rank).isEqualTo(SearchResult.TOP_RANK); + } } @Test public void testDataSaverKey_PrioritizedResult() { final String key = "restrict_background"; final Cursor cursor = getDummyCursor(key, WifiSettings.class.getName()); - final List results = mConverter.convertCursor(mSiteMapManager, cursor, + final Set results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); - assertThat(results.get(0).rank).isEqualTo(SearchResult.TOP_RANK); + for (SearchResult result : results) { + assertThat(result.rank).isEqualTo(SearchResult.TOP_RANK); + } } @Test public void testDataUsageKey_PrioritizedResult() { final String key = "data_usage_enable"; final Cursor cursor = getDummyCursor(key, WifiSettings.class.getName()); - final List results = mConverter.convertCursor(mSiteMapManager, cursor, + final Set results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); - - assertThat(results.get(0).rank).isEqualTo(SearchResult.TOP_RANK); + for (SearchResult result : results) { + assertThat(result.rank).isEqualTo(SearchResult.TOP_RANK); + } } @Test public void testRoamingKey_PrioritizedResult() { final String key = "button_roaming_key"; final Cursor cursor = getDummyCursor(key, WifiSettings.class.getName()); - final List results = mConverter.convertCursor(mSiteMapManager, cursor, + final Set results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK); - assertThat(results.get(0).rank).isEqualTo(SearchResult.TOP_RANK); + for (SearchResult result : results) { + assertThat(result.rank).isEqualTo(SearchResult.TOP_RANK); + } } // End of temporary tests private MatrixCursor getDummyCursor() { - return getDummyCursor(true /* hasIcon */, KEY, "" /* className */); + String[] keys = new String[] {KEY + "1", KEY + "2", KEY + "3"}; + return getDummyCursor(keys, "" /* className */); } private MatrixCursor getDummyCursor(String key, String className) { - return getDummyCursor(false, key, className); + String[] keys = new String[] {key}; + return getDummyCursor(keys, className); } - private MatrixCursor getDummyCursor(boolean hasIcon, String key, String className) { + private MatrixCursor getDummyCursor(String[] keys, String className) { MatrixCursor cursor = new MatrixCursor(DatabaseResultLoader.SELECT_COLUMNS); final String BLANK = ""; final byte[] payload = ResultPayloadUtils.marshall(new ResultPayload(INTENT)); - for (int i = 0; i < EXAMPLES; i++) { + for (int i = 0; i < keys.length; i++) { ArrayList item = new ArrayList<>(DatabaseResultLoader.SELECT_COLUMNS.length); - item.add(ID + i); // Doc ID - item.add(TITLES[i]); // Title + item.add(keys[i].hashCode()); // Doc ID + item.add(TITLES.get(i)); // Title item.add(SUMMARY); // Summary on item.add(BLANK); // summary off item.add(className); // classname item.add(BLANK); // screen title - item.add(hasIcon ? Integer.toString(ICON) : null); // Icon + item.add(null); // Icon item.add(INTENT.getAction()); // Intent action item.add(TARGET_PACKAGE); // target package item.add(TARGET_CLASS); // target class - item.add(key); // Key + item.add(keys[i]); // Key item.add(Integer.toString(0)); // Payload Type item.add(payload); // Payload diff --git a/tests/robotests/src/com/android/settings/search/DatabaseResultLoaderTest.java b/tests/robotests/src/com/android/settings/search/DatabaseResultLoaderTest.java index 47824097b02..bcd33715c08 100644 --- a/tests/robotests/src/com/android/settings/search/DatabaseResultLoaderTest.java +++ b/tests/robotests/src/com/android/settings/search/DatabaseResultLoaderTest.java @@ -45,7 +45,6 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import java.util.ArrayList; import java.util.List; import static com.google.common.truth.Truth.assertThat; @@ -64,16 +63,6 @@ public class DatabaseResultLoaderTest { @Mock private SiteMapManager mSiteMapManager; private Context mContext; - private DatabaseResultLoader loader; - private ResultPayload mResultPayload; - - private final String titleOne = "titleOne"; - private final String titleTwo = "titleTwo"; - private final String titleThree = "titleThree"; - private final String titleFour = "titleFour"; - private final String summaryOne = "summaryOne"; - private final String summaryTwo = "summaryTwo"; - private final String summaryThree = "summaryThree"; SQLiteDatabase mDb; @@ -81,7 +70,6 @@ public class DatabaseResultLoaderTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mResultPayload = new ResultPayload(new Intent()); FakeFeatureFactory.setupForTest(mMockContext); FakeFeatureFactory factory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mMockContext); @@ -98,285 +86,141 @@ public class DatabaseResultLoaderTest { @Test public void testMatchTitle() { - loader = new DatabaseResultLoader(mContext, "title", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "title", mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(2); verify(mSiteMapManager, times(2)).buildBreadCrumb(eq(mContext), anyString(), anyString()); } @Test public void testMatchSummary() { - loader = new DatabaseResultLoader(mContext, "summary", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "summary", + mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(2); } @Test public void testMatchKeywords() { - loader = new DatabaseResultLoader(mContext, "keywords", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "keywords", + mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(2); } @Test public void testMatchEntries() { - loader = new DatabaseResultLoader(mContext, "entries", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "entries", + mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(2); } @Test public void testSpecialCaseWord_matchesNonPrefix() { insertSpecialCase("Data usage"); - loader = new DatabaseResultLoader(mContext, "usage", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "usage", mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test public void testSpecialCaseSpace_matches() { insertSpecialCase("space"); - loader = new DatabaseResultLoader(mContext, " space ", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, " space ", + mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test public void testSpecialCaseDash_matchesWordNoDash() { insertSpecialCase("wi-fi calling"); - loader = new DatabaseResultLoader(mContext, "wifi", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "wifi", mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test public void testSpecialCaseDash_matchesWordWithDash() { insertSpecialCase("priorités seulment"); - loader = new DatabaseResultLoader(mContext, "priorités", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "priorités", + mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test public void testSpecialCaseDash_matchesWordWithoutDash() { insertSpecialCase("priorités seulment"); - loader = new DatabaseResultLoader(mContext, "priorites", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "priorites", + mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test public void testSpecialCaseDash_matchesEntireQueryWithoutDash() { insertSpecialCase("wi-fi calling"); - loader = new DatabaseResultLoader(mContext, "wifi calling", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "wifi calling", + mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test public void testSpecialCasePrefix_matchesPrefixOfEntry() { insertSpecialCase("Photos"); - loader = new DatabaseResultLoader(mContext, "pho", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "pho", mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test public void testSpecialCasePrefix_DoesNotMatchNonPrefixSubstring() { insertSpecialCase("Photos"); - loader = new DatabaseResultLoader(mContext, "hot", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "hot", mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(0); } @Test public void testSpecialCaseMultiWordPrefix_matchesPrefixOfEntry() { insertSpecialCase("Apps Notifications"); - loader = new DatabaseResultLoader(mContext, "Apps", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "Apps", mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test public void testSpecialCaseMultiWordPrefix_matchesSecondWordPrefixOfEntry() { insertSpecialCase("Apps Notifications"); - loader = new DatabaseResultLoader(mContext, "Not", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "Not", mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test public void testSpecialCaseMultiWordPrefix_DoesNotMatchMatchesPrefixOfFirstEntry() { insertSpecialCase("Apps Notifications"); - loader = new DatabaseResultLoader(mContext, "pp", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "pp", mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(0); } @Test public void testSpecialCaseMultiWordPrefix_DoesNotMatchMatchesPrefixOfSecondEntry() { insertSpecialCase("Apps Notifications"); - loader = new DatabaseResultLoader(mContext, "tion", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "tion", mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(0); } @Test public void testSpecialCaseMultiWordPrefixWithSpecial_matchesPrefixOfEntry() { insertSpecialCase("Apps & Notifications"); - loader = new DatabaseResultLoader(mContext, "App", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "App", mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test public void testSpecialCaseMultiWordPrefixWithSpecial_matchesPrefixOfSecondEntry() { insertSpecialCase("Apps & Notifications"); - loader = new DatabaseResultLoader(mContext, "No", mSiteMapManager); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "No", mSiteMapManager); assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test - public void testDeDupe_noDuplicates_originalListReturn() { - // Three elements with unique titles and summaries - List results = new ArrayList(); + public void testResultMatchedByMultipleQueries_duplicatesRemoved() { + String key = "durr"; + insertSameValueAllFieldsCase(key); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, key, null); - SearchResult.Builder builder = new SearchResult.Builder(); - builder.addTitle(titleOne) - .addSummary(summaryOne) - .addPayload(mResultPayload); - SearchResult resultOne = builder.build(); - results.add(resultOne); - - builder.addTitle(titleTwo) - .addSummary(summaryTwo); - SearchResult resultTwo = builder.build(); - results.add(resultTwo); - - builder.addTitle(titleThree) - .addSummary(summaryThree); - SearchResult resultThree = builder.build(); - results.add(resultThree); - - loader = new DatabaseResultLoader(mContext, "", null); - loader.removeDuplicates(results); - assertThat(results.size()).isEqualTo(3); - assertThat(results.get(0)).isEqualTo(resultOne); - assertThat(results.get(1)).isEqualTo(resultTwo); - assertThat(results.get(2)).isEqualTo(resultThree); - } - - @Test - public void testDeDupe_oneDuplicate_duplicateRemoved() { - List results = new ArrayList(); - - SearchResult.Builder builder = new SearchResult.Builder(); - builder.addTitle(titleOne) - .addSummary(summaryOne) - .addRank(0) - .addPayload(mResultPayload); - SearchResult resultOne = builder.build(); - results.add(resultOne); - - // Duplicate of the first element - builder.addTitle(titleOne) - .addSummary(summaryOne) - .addRank(1); - SearchResult resultTwo = builder.build(); - results.add(resultTwo); - - // Unique - builder.addTitle(titleThree) - .addSummary(summaryThree); - SearchResult resultThree = builder.build(); - results.add(resultThree); - - loader = new DatabaseResultLoader(mContext, "", null); - loader.removeDuplicates(results); - assertThat(results.size()).isEqualTo(2); - assertThat(results.get(0)).isEqualTo(resultOne); - assertThat(results.get(1)).isEqualTo(resultThree); - } - - @Test - public void testDeDupe_firstDupeInline_secondDuplicateRemoved() { - List results = new ArrayList(); - InlineSwitchPayload inlinePayload = new InlineSwitchPayload("", 0, null, null); - - SearchResult.Builder builder = new SearchResult.Builder(); - // Inline result - builder.addTitle(titleOne) - .addSummary(summaryOne) - .addRank(0) - .addPayload(inlinePayload); - SearchResult resultOne = builder.build(); - results.add(resultOne); - - // Duplicate of first result, but Intent Result. Should be removed. - builder.addTitle(titleOne) - .addSummary(summaryOne) - .addRank(1) - .addPayload(mResultPayload); - SearchResult resultTwo = builder.build(); - results.add(resultTwo); - - // Unique - builder.addTitle(titleThree) - .addSummary(summaryThree); - SearchResult resultThree = builder.build(); - results.add(resultThree); - - loader = new DatabaseResultLoader(mContext, "", null); - loader.removeDuplicates(results); - assertThat(results.size()).isEqualTo(2); - assertThat(results.get(0)).isEqualTo(resultOne); - assertThat(results.get(1)).isEqualTo(resultThree); - } - - @Test - public void testDeDupe_secondDupeInline_firstDuplicateRemoved() { - /* - * Create a list as follows: - * (5) Intent Four - * (4) Inline Two - * (3) Intent Three - * (2) Intent Two - * (1) Intent One - * - * After removing duplicates: - * (4) Intent Four - * (3) Inline Two - * (2) Intent Three - * (1) Intent One - */ - List results = new ArrayList(); - InlineSwitchPayload inlinePayload = new InlineSwitchPayload("", 0, null, null); - - SearchResult.Builder builder = new SearchResult.Builder(); - // Intent One - builder.addTitle(titleOne) - .addSummary(summaryOne) - .addPayload(mResultPayload); - SearchResult resultOne = builder.build(); - results.add(resultOne); - - // Intent Two - builder.addTitle(titleTwo) - .addSummary(summaryTwo) - .addPayload(mResultPayload); - SearchResult resultTwo = builder.build(); - results.add(resultTwo); - - // Intent Three - builder.addTitle(titleThree) - .addSummary(summaryThree); - SearchResult resultThree = builder.build(); - results.add(resultThree); - - // Inline Two - builder.addTitle(titleTwo) - .addSummary(summaryTwo) - .addPayload(inlinePayload); - SearchResult resultFour = builder.build(); - results.add(resultFour); - - // Intent Four - builder.addTitle(titleFour) - .addSummary(summaryOne) - .addPayload(mResultPayload); - SearchResult resultFive = builder.build(); - results.add(resultFive); - - loader = new DatabaseResultLoader(mContext, "", null); - loader.removeDuplicates(results); - assertThat(results.size()).isEqualTo(4); - assertThat(results.get(0)).isEqualTo(resultOne); - assertThat(results.get(1)).isEqualTo(resultThree); - assertThat(results.get(2)).isEqualTo(resultFour); - assertThat(results.get(3)).isEqualTo(resultFive); + assertThat(loader.loadInBackground().size()).isEqualTo(1); } @Test @@ -385,7 +229,7 @@ public class DatabaseResultLoaderTest { final String caseTwo = "Banana apple"; insertSpecialCase(caseOne); insertSpecialCase(caseTwo); - loader = new DatabaseResultLoader(mContext, "App", null); + DatabaseResultLoader loader = new DatabaseResultLoader(mContext, "App", null); List results = loader.loadInBackground(); assertThat(results.get(0).title).isEqualTo(caseOne); @@ -418,7 +262,7 @@ public class DatabaseResultLoaderTest { values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, ""); values.put(IndexDatabaseHelper.IndexColumns.ICON, ""); values.put(IndexDatabaseHelper.IndexColumns.ENABLED, true); - values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, normalized.hashCode()); values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0); values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0); values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, ResultPayloadUtils.marshall(payload)); @@ -430,7 +274,7 @@ public class DatabaseResultLoaderTest { final byte[] payload = ResultPayloadUtils.marshall(new ResultPayload(new Intent())); ContentValues values = new ContentValues(); - values.put(IndexDatabaseHelper.IndexColumns.DOCID, 0); + values.put(IndexDatabaseHelper.IndexColumns.DOCID, 1); values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us"); values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1); values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, "alpha_title"); @@ -449,7 +293,7 @@ public class DatabaseResultLoaderTest { values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, ""); values.put(IndexDatabaseHelper.IndexColumns.ICON, ""); values.put(IndexDatabaseHelper.IndexColumns.ENABLED, true); - values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power_0"); values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0); values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0); values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, payload); @@ -457,7 +301,7 @@ public class DatabaseResultLoaderTest { mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values); values = new ContentValues(); - values.put(IndexDatabaseHelper.IndexColumns.DOCID, 1); + values.put(IndexDatabaseHelper.IndexColumns.DOCID, 2); values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us"); values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1); values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, "bravo_title"); @@ -476,14 +320,14 @@ public class DatabaseResultLoaderTest { values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, ""); values.put(IndexDatabaseHelper.IndexColumns.ICON, ""); values.put(IndexDatabaseHelper.IndexColumns.ENABLED, true); - values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power_1"); values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0); values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0); values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, payload); mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values); values = new ContentValues(); - values.put(IndexDatabaseHelper.IndexColumns.DOCID, 2); + values.put(IndexDatabaseHelper.IndexColumns.DOCID, 3); values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us"); values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1); values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, "charlie_title"); @@ -502,11 +346,41 @@ public class DatabaseResultLoaderTest { values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, ""); values.put(IndexDatabaseHelper.IndexColumns.ICON, ""); values.put(IndexDatabaseHelper.IndexColumns.ENABLED, false); - values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power_2"); values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0); values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0); values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, payload); mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values); } + + private void insertSameValueAllFieldsCase(String key) { + final ResultPayload payload = new ResultPayload(new Intent()); + + ContentValues values = new ContentValues(); + values.put(IndexDatabaseHelper.IndexColumns.DOCID, key.hashCode()); + values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1); + values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, key); + values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, key); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, key); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, key); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, key); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, key); + values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, key); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, key); + values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME, key); + values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves"); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, key); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, ""); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, key); + values.put(IndexDatabaseHelper.IndexColumns.ICON, ""); + values.put(IndexDatabaseHelper.IndexColumns.ENABLED, true); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, key.hashCode()); + values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0); + values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0); + values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, ResultPayloadUtils.marshall(payload)); + + mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values); + } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/search/InlineSwitchViewHolderTest.java b/tests/robotests/src/com/android/settings/search/InlineSwitchViewHolderTest.java index 362184716cb..65d99f4256e 100644 --- a/tests/robotests/src/com/android/settings/search/InlineSwitchViewHolderTest.java +++ b/tests/robotests/src/com/android/settings/search/InlineSwitchViewHolderTest.java @@ -110,13 +110,14 @@ public class InlineSwitchViewHolderTest { private SearchResult getSearchResult() { SearchResult.Builder builder = new SearchResult.Builder(); - builder.addTitle(TITLE) - .addSummary(SUMMARY) - .addRank(1) - .addPayload(new InlineSwitchPayload("", 0, null, null)) + builder.setTitle(TITLE) + .setSummary(SUMMARY) + .setRank(1) + .setPayload(new InlineSwitchPayload("", 0, null, null)) .addBreadcrumbs(new ArrayList<>()) - .addIcon(mIcon) - .addPayload(mPayload); + .setIcon(mIcon) + .setPayload(mPayload) + .setStableId(TITLE.hashCode()); return builder.build(); } diff --git a/tests/robotests/src/com/android/settings/search/IntentSearchViewHolderTest.java b/tests/robotests/src/com/android/settings/search/IntentSearchViewHolderTest.java index 9d0add62d81..ee1c913b699 100644 --- a/tests/robotests/src/com/android/settings/search/IntentSearchViewHolderTest.java +++ b/tests/robotests/src/com/android/settings/search/IntentSearchViewHolderTest.java @@ -47,6 +47,7 @@ import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; @@ -120,10 +121,11 @@ public class IntentSearchViewHolderTest { @Test public void testBindViewElements_emptySummary_hideSummaryView() { final SearchResult result = new Builder() - .addTitle(TITLE) - .addRank(1) - .addPayload(new ResultPayload(null)) - .addIcon(mIcon) + .setTitle(TITLE) + .setRank(1) + .setPayload(new ResultPayload(null)) + .setIcon(mIcon) + .setStableId(1) .build(); mHolder.onBind(mFragment, result); @@ -137,11 +139,12 @@ public class IntentSearchViewHolderTest { breadcrumbs.add("b"); breadcrumbs.add("c"); final SearchResult result = new Builder() - .addTitle(TITLE) - .addRank(1) - .addPayload(new ResultPayload(null)) + .setTitle(TITLE) + .setRank(1) + .setPayload(new ResultPayload(null)) .addBreadcrumbs(breadcrumbs) - .addIcon(mIcon) + .setIcon(mIcon) + .setStableId(1) .build(); mHolder.onBind(mFragment, result); @@ -153,9 +156,10 @@ public class IntentSearchViewHolderTest { public void testBindElements_placeholderSummary_visibilityIsGone() { String nonBreakingSpace = mContext.getString(R.string.summary_placeholder); SearchResult result = new Builder() - .addTitle(TITLE) - .addSummary(nonBreakingSpace) - .addPayload(new ResultPayload(null)) + .setTitle(TITLE) + .setSummary(nonBreakingSpace) + .setPayload(new ResultPayload(null)) + .setStableId(1) .build(); mHolder.onBind(mFragment, result); @@ -165,13 +169,15 @@ public class IntentSearchViewHolderTest { private SearchResult getSearchResult(String title, String summary, Drawable icon) { Builder builder = new Builder(); - builder.addTitle(title) - .addSummary(summary) - .addRank(1) - .addPayload(new ResultPayload( + builder.setStableId(Objects.hash(title, summary, icon)) + .setTitle(title) + .setSummary(summary) + .setRank(1) + .setPayload(new ResultPayload( new Intent().setComponent(new ComponentName("pkg", "class")))) .addBreadcrumbs(new ArrayList<>()) - .addIcon(icon); + .setStableId(1) + .setIcon(icon); return builder.build(); } diff --git a/tests/robotests/src/com/android/settings/search/SearchResultBuilderTest.java b/tests/robotests/src/com/android/settings/search/SearchResultBuilderTest.java index 8bf4d5ede14..cb4bc415fd5 100644 --- a/tests/robotests/src/com/android/settings/search/SearchResultBuilderTest.java +++ b/tests/robotests/src/com/android/settings/search/SearchResultBuilderTest.java @@ -40,9 +40,10 @@ import static com.google.common.truth.Truth.assertThat; @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class SearchResultBuilderTest { + private static final String TITLE = "title"; + private static final String SUMMARY = "summary"; + private Builder mBuilder; - private String mTitle; - private String mSummary; private ArrayList mBreadcrumbs; private int mRank; private ResultPayload mResultPayload; @@ -51,8 +52,6 @@ public class SearchResultBuilderTest { @Before public void setUp() { mBuilder = new Builder(); - mTitle = "title"; - mSummary = "summary"; mBreadcrumbs = new ArrayList<>(); mRank = 3; mResultPayload = new ResultPayload(new Intent()); @@ -63,77 +62,82 @@ public class SearchResultBuilderTest { @Test public void testAllInfo_BuildSearchResult() { - mBuilder.addTitle(mTitle) - .addSummary(mSummary) - .addRank(mRank) + mBuilder.setTitle(TITLE) + .setSummary(SUMMARY) + .setRank(mRank) .addBreadcrumbs(mBreadcrumbs) - .addIcon(mIcon) - .addPayload(mResultPayload); + .setIcon(mIcon) + .setPayload(mResultPayload) + .setStableId(1); SearchResult result = mBuilder.build(); assertThat(result).isNotNull(); - assertThat(result.title).isEqualTo(mTitle); - assertThat(result.summary).isEqualTo(mSummary); + assertThat(result.title).isEqualTo(TITLE); + assertThat(result.summary).isEqualTo(SUMMARY); assertThat(result.rank).isEqualTo(mRank); assertThat(result.breadcrumbs).isEqualTo(mBreadcrumbs); assertThat(result.icon).isEqualTo(mIcon); assertThat(result.payload).isEqualTo(mResultPayload); } - @Test - public void testNoTitle_BuildSearchResultException() { - mBuilder.addSummary(mSummary) - .addRank(mRank) + @Test(expected = IllegalStateException.class) + public void testNoStableId_BuildSearchResultException() { + mBuilder.setTitle(TITLE) + .setSummary(SUMMARY) + .setRank(mRank) .addBreadcrumbs(mBreadcrumbs) - .addIcon(mIcon) - .addPayload(mResultPayload); + .setIcon(mIcon) + .setPayload(mResultPayload); - SearchResult result = null; - try { - result = mBuilder.build(); - } catch (IllegalArgumentException e) { - // passes. - } - assertThat(result).isNull(); + mBuilder.build(); + } + + @Test(expected = IllegalStateException.class) + public void testNoTitle_BuildSearchResultException() { + mBuilder.setSummary(SUMMARY) + .setRank(mRank) + .addBreadcrumbs(mBreadcrumbs) + .setIcon(mIcon) + .setPayload(mResultPayload) + .setStableId(1); + + mBuilder.build(); } @Test public void testNoRank_BuildSearchResult_pass() { - mBuilder.addTitle(mTitle) - .addSummary(mSummary) + mBuilder.setTitle(TITLE) + .setSummary(SUMMARY) .addBreadcrumbs(mBreadcrumbs) - .addIcon(mIcon) - .addPayload(mResultPayload); + .setIcon(mIcon) + .setPayload(mResultPayload) + .setStableId(1); assertThat(mBuilder.build()).isNotNull(); } @Test public void testNoIcon_BuildSearchResult_pass() { - mBuilder.addTitle(mTitle) - .addSummary(mSummary) - .addRank(mRank) + mBuilder.setTitle(TITLE) + .setSummary(SUMMARY) + .setRank(mRank) .addBreadcrumbs(mBreadcrumbs) - .addPayload(mResultPayload); + .setPayload(mResultPayload) + .setStableId(1); assertThat(mBuilder.build()).isNotNull(); } - @Test + @Test(expected = IllegalStateException.class) public void testNoPayload_BuildSearchResultException() { - mBuilder.addTitle(mTitle) - .addSummary(mSummary) - .addRank(mRank) + mBuilder.setTitle(TITLE) + .setSummary(SUMMARY) + .setRank(mRank) .addBreadcrumbs(mBreadcrumbs) - .addIcon(mIcon); + .setIcon(mIcon) + .setStableId(1); - SearchResult result = null; - try { - result = mBuilder.build(); - } catch (IllegalArgumentException e) { - // passes. - } - assertThat(result).isNull(); + mBuilder.build(); } } diff --git a/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java b/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java index c7007589b9d..5af85506554 100644 --- a/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java +++ b/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java @@ -47,6 +47,7 @@ import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import static com.google.common.truth.Truth.assertThat; @@ -188,18 +189,20 @@ public class SearchResultsAdapterTest { List results = new ArrayList<>(); ResultPayload payload = new ResultPayload(new Intent()); SearchResult.Builder builder = new SearchResult.Builder(); - builder.addPayload(payload); - - builder.addTitle(TITLES[0]) - .addRank(1); + builder.setPayload(payload) + .setTitle(TITLES[0]) + .setRank(1) + .setStableId(Objects.hash(TITLES[0], "db")); results.add(builder.build()); - builder.addTitle(TITLES[1]) - .addRank(3); + builder.setTitle(TITLES[1]) + .setRank(3) + .setStableId(Objects.hash(TITLES[1], "db")); results.add(builder.build()); - builder.addTitle(TITLES[2]) - .addRank(6); + builder.setTitle(TITLES[2]) + .setRank(6) + .setStableId(Objects.hash(TITLES[2], "db")); results.add(builder.build()); return results; @@ -209,18 +212,20 @@ public class SearchResultsAdapterTest { List results = new ArrayList<>(); ResultPayload payload = new ResultPayload(new Intent()); AppSearchResult.Builder builder = new AppSearchResult.Builder(); - builder.addPayload(payload); - - builder.addTitle(TITLES[3]) - .addRank(1); + builder.setPayload(payload) + .setTitle(TITLES[3]) + .setRank(1) + .setStableId(Objects.hash(TITLES[3], "app")); results.add(builder.build()); - builder.addTitle(TITLES[4]) - .addRank(2); + builder.setTitle(TITLES[4]) + .setRank(2) + .setStableId(Objects.hash(TITLES[4], "app")); results.add(builder.build()); - builder.addTitle(TITLES[5]) - .addRank(4); + builder.setTitle(TITLES[5]) + .setRank(4) + .setStableId(Objects.hash(TITLES[5], "app")); results.add(builder.build()); return results; @@ -232,18 +237,21 @@ public class SearchResultsAdapterTest { final Drawable icon = mContext.getDrawable(R.drawable.ic_search_history); final ResultPayload payload = new ResultPayload(null); final SearchResult.Builder builder = new Builder(); - builder.addTitle("title") - .addSummary("summary") - .addRank(1) + builder.setTitle("title") + .setSummary("summary") + .setRank(1) .addBreadcrumbs(breadcrumbs) - .addIcon(icon) - .addPayload(payload); + .setIcon(icon) + .setPayload(payload) + .setStableId(Objects.hash("title", "summary", 1)); sampleResults.add(builder.build()); - builder.addRank(2); + builder.setRank(2) + .setStableId(Objects.hash("title", "summary", 2)); sampleResults.add(builder.build()); - builder.addRank(3); + builder.setRank(3) + .setStableId(Objects.hash("title", "summary", 3)); sampleResults.add(builder.build()); return sampleResults; }