1/*
2 * Copyright (C) 2010 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
17package com.android.quicksearchbox;
18
19import android.test.AndroidTestCase;
20import android.test.suitebuilder.annotation.SmallTest;
21
22import java.util.ArrayList;
23import java.util.List;
24
25/**
26 * Tests for RankAwarePromoter
27 */
28@SmallTest
29public class RankAwarePromoterTest extends AndroidTestCase {
30    public static final int NUM_SUGGESTIONS_ABOVE_KEYBOARD = 4;
31    public static final int MAX_PROMOTED_CORPORA = 3;
32    public static final int MAX_PROMOTED_SUGGESTIONS = 8;
33    public static final String TEST_QUERY = "query";
34
35    private final List<Corpus> mCorpora = createMockCorpora(5, MAX_PROMOTED_CORPORA);
36    private final Corpus mShortcuts = createMockShortcutsCorpus();
37    private RankAwarePromoter mPromoter;
38
39    @Override
40    public void setUp() {
41        mPromoter = new RankAwarePromoter(new Config(mContext){
42            @Override
43            public int getNumSuggestionsAboveKeyboard() {
44                return NUM_SUGGESTIONS_ABOVE_KEYBOARD;
45            }
46        }, null, null);
47    }
48
49    public void testPromotesExpectedSuggestions() {
50        List<CorpusResult> suggestions = getSuggestions(TEST_QUERY);
51        ListSuggestionCursorNoDuplicates promoted =
52            new ListSuggestionCursorNoDuplicates(TEST_QUERY);
53        mPromoter.promoteSuggestions(suggestions, MAX_PROMOTED_SUGGESTIONS, promoted);
54
55        int[] expectedSource = {0, 1, 2, 0, 1, 2, 3, 4};
56        int[] expectedSuggestion = {1, 1, 1, 2, 2, 2, 1, 1};
57
58        assertRightSuggestionsWerePromoted(promoted, expectedSource, expectedSuggestion);
59    }
60
61    public void testWhenPromotingAlreadyPromotedResults() {
62        List<CorpusResult> suggestions = getSuggestions(TEST_QUERY);
63        ListSuggestionCursorNoDuplicates promoted =
64                new ListSuggestionCursorNoDuplicates(TEST_QUERY);
65
66        // Simulate scenario where another promoter has already put an item
67        // (e.g. a shortcut) into the promoted suggestions list, and the current
68        // promoter tries to promote the same item.
69        // The promoter must notice that this duplicate (which automatically
70        // gets filtered out by the suggestion cursor) doesn't decrease the
71        // number of slots available on the screen.
72        CorpusResult corpora2 = suggestions.get(2);
73        corpora2.moveTo(0);
74        Suggestion shortcut = new SuggestionPosition(corpora2);
75        promoted.add(shortcut);
76
77        mPromoter.promoteSuggestions(suggestions, MAX_PROMOTED_SUGGESTIONS, promoted);
78
79        int[] expectedSource = {
80                // The shortcut at the top of the list.
81                2,
82                // The promoted results. There's just one result from corpus
83                // 2 because only 2 test suggestions per corpus are generated
84                // by the test data generator, and we use up all our suggestions
85                // for corpus 2 earlier than the rest.
86                0, 1, 2, 0, 1, 3, 4};
87        int[] expectedSuggestion = {
88                // The shortcut at the top of the list.
89                1,
90                // The promoted results.
91                1, 1, 2, 2, 2, 1, 1};
92
93        assertRightSuggestionsWerePromoted(promoted, expectedSource, expectedSuggestion);
94    }
95
96    private void assertRightSuggestionsWerePromoted(ListSuggestionCursorNoDuplicates promoted,
97            int[] expectedSource, int[] expectedSuggestion) {
98        assertEquals(MAX_PROMOTED_SUGGESTIONS, promoted.getCount());
99
100        for (int i = 0; i < promoted.getCount(); i++) {
101            promoted.moveTo(i);
102            assertEquals("Source in position " + i,
103                    "MockSource Source" + expectedSource[i],
104                    promoted.getSuggestionSource().getLabel());
105            assertEquals("Suggestion in position " + i,
106                    TEST_QUERY + "_" + expectedSuggestion[i],
107                    promoted.getSuggestionText1());
108        }
109    }
110
111    public void testPromotesRightNumberOfSuggestions() {
112        List<CorpusResult> suggestions = getSuggestions(TEST_QUERY);
113        ListSuggestionCursor promoted = new ListSuggestionCursor(TEST_QUERY);
114        SuggestionCursor shortcuts = mShortcuts.
115                getSuggestions(TEST_QUERY, MAX_PROMOTED_SUGGESTIONS / 2, true);
116        for (int i = 0; i < shortcuts.getCount(); ++i) {
117            promoted.add(new SuggestionPosition(shortcuts, 1));
118        }
119        mPromoter.promoteSuggestions(suggestions, MAX_PROMOTED_SUGGESTIONS, promoted);
120        assertEquals(MAX_PROMOTED_SUGGESTIONS, promoted.getCount());
121    }
122
123    private List<CorpusResult> getSuggestions(String query) {
124        ArrayList<CorpusResult> results = new ArrayList<CorpusResult>();
125        for (Corpus corpus : mCorpora) {
126            results.add(corpus.getSuggestions(query, 10, false));
127        }
128        return results;
129    }
130
131    private static List<Corpus> createMockCorpora(int count, int defaultCount) {
132        ArrayList<Corpus> corpora = new ArrayList<Corpus>();
133        for (int i = 0; i < count; i++) {
134            Source mockSource = new MockSource("Source" + i);
135            Corpus mockCorpus = new MockCorpus(mockSource, i < defaultCount);
136            corpora.add(mockCorpus);
137        }
138        return corpora;
139    }
140
141    private static Corpus createMockShortcutsCorpus() {
142        Source mockSource = new MockSource("Shortcuts");
143        Corpus mockCorpus = new MockCorpus(mockSource, true);
144        return mockCorpus;
145    }
146
147}
148