1/* 2 * Copyright (C) 2017 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 androidx.appcompat.widget; 18 19import static org.junit.Assert.assertEquals; 20import static org.junit.Assert.assertFalse; 21import static org.junit.Assert.assertTrue; 22import static org.mockito.Mockito.anyString; 23import static org.mockito.Mockito.mock; 24import static org.mockito.Mockito.never; 25import static org.mockito.Mockito.times; 26import static org.mockito.Mockito.verify; 27import static org.mockito.Mockito.verifyNoMoreInteractions; 28import static org.mockito.Mockito.when; 29 30import android.app.Activity; 31import android.app.Instrumentation; 32import android.content.res.Resources; 33import android.support.test.InstrumentationRegistry; 34import android.support.test.annotation.UiThreadTest; 35import android.support.test.filters.MediumTest; 36import android.support.test.rule.ActivityTestRule; 37import android.support.test.runner.AndroidJUnit4; 38import android.text.InputType; 39import android.text.TextUtils; 40import android.view.inputmethod.EditorInfo; 41 42import androidx.appcompat.test.R; 43 44import org.junit.Before; 45import org.junit.Rule; 46import org.junit.Test; 47import org.junit.runner.RunWith; 48 49/** 50 * Test {@link SearchView}. 51 */ 52@MediumTest 53@RunWith(AndroidJUnit4.class) 54public class SearchViewTest { 55 private Instrumentation mInstrumentation; 56 private Activity mActivity; 57 private SearchView mSearchView; 58 59 @Rule 60 public ActivityTestRule<SearchViewTestActivity> mActivityRule = 61 new ActivityTestRule<>(SearchViewTestActivity.class); 62 63 @Before 64 public void setup() { 65 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 66 mActivity = mActivityRule.getActivity(); 67 mSearchView = (SearchView) mActivity.findViewById(R.id.search_view); 68 } 69 70 @UiThreadTest 71 @Test 72 public void testConstructor() { 73 new SearchView(mActivity); 74 75 new SearchView(mActivity, null); 76 77 new SearchView(mActivity, null, android.R.attr.searchViewStyle); 78 } 79 80 @UiThreadTest 81 @Test 82 public void testAttributesFromXml() { 83 SearchView searchViewWithAttributes = 84 (SearchView) mActivity.findViewById(R.id.search_view_with_defaults); 85 assertEquals(mActivity.getString(R.string.search_query_hint), 86 searchViewWithAttributes.getQueryHint()); 87 assertFalse(searchViewWithAttributes.isIconfiedByDefault()); 88 assertEquals(EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS | EditorInfo.TYPE_CLASS_TEXT, 89 searchViewWithAttributes.getInputType()); 90 assertEquals(EditorInfo.IME_ACTION_DONE, searchViewWithAttributes.getImeOptions()); 91 assertEquals(mActivity.getResources().getDimensionPixelSize(R.dimen.search_view_max_width), 92 searchViewWithAttributes.getMaxWidth()); 93 } 94 95 @UiThreadTest 96 @Test 97 public void testAccessIconified() { 98 mSearchView.setIconified(true); 99 assertTrue(mSearchView.isIconified()); 100 101 mSearchView.setIconified(false); 102 assertFalse(mSearchView.isIconified()); 103 } 104 105 @UiThreadTest 106 @Test 107 public void testAccessIconifiedByDefault() { 108 mSearchView.setIconifiedByDefault(true); 109 assertTrue(mSearchView.isIconfiedByDefault()); 110 111 mSearchView.setIconifiedByDefault(false); 112 assertFalse(mSearchView.isIconfiedByDefault()); 113 } 114 115 @Test 116 public void testDenyIconifyingNonInconifiableView() throws Throwable { 117 mActivityRule.runOnUiThread(new Runnable() { 118 @Override 119 public void run() { 120 mSearchView.setIconifiedByDefault(false); 121 mSearchView.setIconified(false); 122 } 123 }); 124 125 mActivityRule.runOnUiThread(new Runnable() { 126 @Override 127 public void run() { 128 mSearchView.setIconified(true); 129 } 130 }); 131 mInstrumentation.waitForIdleSync(); 132 133 // Since our search view is marked with iconifiedByDefault=false, call to setIconified 134 // with true us going to be ignored, as detailed in the class-level documentation of 135 // SearchView. 136 assertFalse(mSearchView.isIconified()); 137 } 138 139 @Test 140 public void testDenyIconifyingInconifiableView() throws Throwable { 141 mActivityRule.runOnUiThread(new Runnable() { 142 @Override 143 public void run() { 144 mSearchView.setIconifiedByDefault(true); 145 mSearchView.setIconified(false); 146 } 147 }); 148 149 final SearchView.OnCloseListener mockDenyCloseListener = 150 mock(SearchView.OnCloseListener.class); 151 when(mockDenyCloseListener.onClose()).thenReturn(Boolean.TRUE); 152 mSearchView.setOnCloseListener(mockDenyCloseListener); 153 154 mActivityRule.runOnUiThread(new Runnable() { 155 @Override 156 public void run() { 157 mSearchView.setIconified(true); 158 } 159 }); 160 mInstrumentation.waitForIdleSync(); 161 162 // Our mock listener is configured to return true from its onClose, thereby preventing 163 // the iconify request to be completed. Check that the listener was called and that the 164 // search view is not iconified. 165 verify(mockDenyCloseListener, times(1)).onClose(); 166 assertFalse(mSearchView.isIconified()); 167 } 168 169 @Test 170 public void testAllowIconifyingInconifiableView() throws Throwable { 171 mActivityRule.runOnUiThread(new Runnable() { 172 @Override 173 public void run() { 174 mSearchView.setIconifiedByDefault(true); 175 mSearchView.setIconified(false); 176 } 177 }); 178 179 final SearchView.OnCloseListener mockAllowCloseListener = 180 mock(SearchView.OnCloseListener.class); 181 when(mockAllowCloseListener.onClose()).thenReturn(Boolean.FALSE); 182 mSearchView.setOnCloseListener(mockAllowCloseListener); 183 184 mActivityRule.runOnUiThread(new Runnable() { 185 @Override 186 public void run() { 187 mSearchView.setIconified(true); 188 } 189 }); 190 mInstrumentation.waitForIdleSync(); 191 192 // Our mock listener is configured to return false from its onClose, thereby allowing 193 // the iconify request to be completed. Check that the listener was called and that the 194 // search view is not iconified. 195 verify(mockAllowCloseListener, times(1)).onClose(); 196 assertTrue(mSearchView.isIconified()); 197 } 198 199 @Test 200 public void testAccessMaxWidth() throws Throwable { 201 final Resources res = mActivity.getResources(); 202 final int maxWidth1 = res.getDimensionPixelSize(R.dimen.search_view_max_width); 203 final int maxWidth2 = res.getDimensionPixelSize(R.dimen.search_view_max_width2); 204 205 // Set search view to not be iconified before running max-width tests 206 mActivityRule.runOnUiThread(new Runnable() { 207 @Override 208 public void run() { 209 mSearchView.setIconified(false); 210 } 211 }); 212 213 mActivityRule.runOnUiThread(new Runnable() { 214 @Override 215 public void run() { 216 mSearchView.setMaxWidth(maxWidth1); 217 } 218 }); 219 mInstrumentation.waitForIdleSync(); 220 assertEquals(maxWidth1, mSearchView.getMaxWidth()); 221 assertTrue(mSearchView.getWidth() <= maxWidth1); 222 223 mActivityRule.runOnUiThread(new Runnable() { 224 @Override 225 public void run() { 226 mSearchView.setMaxWidth(maxWidth2); 227 } 228 }); 229 mInstrumentation.waitForIdleSync(); 230 assertEquals(maxWidth2, mSearchView.getMaxWidth()); 231 assertTrue(mSearchView.getWidth() <= maxWidth2); 232 } 233 234 @UiThreadTest 235 @Test 236 public void testAccessQuery() { 237 mSearchView.setIconified(false); 238 239 final SearchView.OnQueryTextListener mockQueryTextListener = 240 mock(SearchView.OnQueryTextListener.class); 241 when(mockQueryTextListener.onQueryTextSubmit(anyString())).thenReturn(Boolean.TRUE); 242 mSearchView.setOnQueryTextListener(mockQueryTextListener); 243 244 mSearchView.setQuery("alpha", false); 245 assertTrue(TextUtils.equals("alpha", mSearchView.getQuery())); 246 // Since we passed false as the second parameter to setQuery, our query text listener 247 // should have been invoked only with text change 248 verify(mockQueryTextListener, times(1)).onQueryTextChange("alpha"); 249 verify(mockQueryTextListener, never()).onQueryTextSubmit(anyString()); 250 251 mSearchView.setQuery("beta", true); 252 assertTrue(TextUtils.equals("beta", mSearchView.getQuery())); 253 // Since we passed true as the second parameter to setQuery, our query text listener 254 // should have been invoked on both callbacks 255 verify(mockQueryTextListener, times(1)).onQueryTextChange("beta"); 256 verify(mockQueryTextListener, times(1)).onQueryTextSubmit("beta"); 257 258 mSearchView.setQuery("gamma", true); 259 assertTrue(TextUtils.equals("gamma", mSearchView.getQuery())); 260 // Since we passed true as the second parameter to setQuery, our query text listener 261 // should have been invoked on both callbacks 262 verify(mockQueryTextListener, times(1)).onQueryTextChange("gamma"); 263 verify(mockQueryTextListener, times(1)).onQueryTextSubmit("gamma"); 264 265 verifyNoMoreInteractions(mockQueryTextListener); 266 } 267 268 @UiThreadTest 269 @Test 270 public void testAccessQueryHint() { 271 mSearchView.setQueryHint("hint 1"); 272 assertTrue(TextUtils.equals("hint 1", mSearchView.getQueryHint())); 273 274 mSearchView.setQueryHint("hint 2"); 275 assertTrue(TextUtils.equals("hint 2", mSearchView.getQueryHint())); 276 } 277 278 @UiThreadTest 279 @Test 280 public void testAccessInputType() { 281 mSearchView.setInputType(InputType.TYPE_CLASS_NUMBER 282 | InputType.TYPE_NUMBER_FLAG_DECIMAL 283 | InputType.TYPE_NUMBER_FLAG_SIGNED); 284 assertEquals(InputType.TYPE_CLASS_NUMBER 285 | InputType.TYPE_NUMBER_FLAG_DECIMAL 286 | InputType.TYPE_NUMBER_FLAG_SIGNED, mSearchView.getInputType()); 287 288 mSearchView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_WORDS); 289 assertEquals(InputType.TYPE_CLASS_TEXT 290 | InputType.TYPE_TEXT_FLAG_CAP_WORDS, mSearchView.getInputType()); 291 292 mSearchView.setInputType(InputType.TYPE_CLASS_PHONE); 293 assertEquals(InputType.TYPE_CLASS_PHONE, mSearchView.getInputType()); 294 } 295 296 @UiThreadTest 297 @Test 298 public void testAccessImeOptions() { 299 mSearchView.setImeOptions(EditorInfo.IME_ACTION_GO); 300 assertEquals(EditorInfo.IME_ACTION_GO, mSearchView.getImeOptions()); 301 302 mSearchView.setImeOptions(EditorInfo.IME_ACTION_DONE); 303 assertEquals(EditorInfo.IME_ACTION_DONE, mSearchView.getImeOptions()); 304 305 mSearchView.setImeOptions(EditorInfo.IME_NULL); 306 assertEquals(EditorInfo.IME_NULL, mSearchView.getImeOptions()); 307 } 308} 309