1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.widget.cts; 18 19 import com.android.cts.stub.R; 20 21 import dalvik.annotation.TestLevel; 22 import dalvik.annotation.TestTargetClass; 23 import dalvik.annotation.TestTargetNew; 24 import dalvik.annotation.TestTargets; 25 import dalvik.annotation.ToBeFixed; 26 27 import org.xmlpull.v1.XmlPullParser; 28 29 import android.app.Activity; 30 import android.content.Context; 31 import android.test.ActivityInstrumentationTestCase2; 32 import android.test.UiThreadTest; 33 import android.text.SpannableString; 34 import android.text.Spanned; 35 import android.text.TextUtils; 36 import android.util.AttributeSet; 37 import android.util.Xml; 38 import android.view.KeyEvent; 39 import android.widget.ArrayAdapter; 40 import android.widget.Filter; 41 import android.widget.MultiAutoCompleteTextView; 42 import android.widget.MultiAutoCompleteTextView.CommaTokenizer; 43 import android.widget.MultiAutoCompleteTextView.Tokenizer; 44 45 @TestTargetClass(MultiAutoCompleteTextView.class) 46 public class MultiAutoCompleteTextViewTest extends ActivityInstrumentationTestCase2 47 <MultiAutoCompleteTextViewStubActivity> { 48 private MultiAutoCompleteTextView mMultiAutoCompleteTextView_country; 49 private MultiAutoCompleteTextView mMultiAutoCompleteTextView_name; 50 private Activity mActivity; 51 MultiAutoCompleteTextViewTest()52 public MultiAutoCompleteTextViewTest() { 53 super("com.android.cts.stub", MultiAutoCompleteTextViewStubActivity.class); 54 } 55 56 @Override setUp()57 protected void setUp() throws Exception { 58 super.setUp(); 59 60 mActivity = getActivity(); 61 62 mMultiAutoCompleteTextView_country = (MultiAutoCompleteTextView)mActivity 63 .findViewById(R.id.country_edit); 64 mMultiAutoCompleteTextView_name = (MultiAutoCompleteTextView)mActivity 65 .findViewById(R.id.name_edit); 66 } 67 68 @TestTargets({ 69 @TestTargetNew( 70 level = TestLevel.COMPLETE, 71 method = "MultiAutoCompleteTextView", 72 args = {android.content.Context.class} 73 ), 74 @TestTargetNew( 75 level = TestLevel.COMPLETE, 76 method = "MultiAutoCompleteTextView", 77 args = {android.content.Context.class, android.util.AttributeSet.class} 78 ), 79 @TestTargetNew( 80 level = TestLevel.COMPLETE, 81 method = "MultiAutoCompleteTextView", 82 args = {android.content.Context.class, android.util.AttributeSet.class, int.class} 83 ) 84 }) 85 @ToBeFixed(bug = "1695243", explanation = "Android API javadocs are incomplete") testConstructor()86 public void testConstructor() { 87 XmlPullParser parser = mActivity.getResources() 88 .getXml(R.layout.multi_auto_complete_text_view_layout); 89 AttributeSet attr = Xml.asAttributeSet(parser); 90 91 new MultiAutoCompleteTextView(mActivity); 92 new MultiAutoCompleteTextView(mActivity, attr); 93 new MultiAutoCompleteTextView(mActivity, attr, 0); 94 95 try { 96 new MultiAutoCompleteTextView(null); 97 fail("There should be a NullPointerException thrown out."); 98 } catch (NullPointerException e) { 99 // expected, test success 100 } 101 102 try { 103 new MultiAutoCompleteTextView(null, null); 104 fail("There should be a NullPointerException thrown out."); 105 } catch (NullPointerException e) { 106 // expected, test success 107 } 108 109 try { 110 new MultiAutoCompleteTextView(null, null, -1); 111 fail("There should be a NullPointerException thrown out."); 112 } catch (NullPointerException e) { 113 // expected, test success 114 } 115 } 116 117 @UiThreadTest setText(MultiAutoCompleteTextView m, CharSequence c)118 private void setText(MultiAutoCompleteTextView m, CharSequence c) { 119 m.setText(c); 120 m.setSelection(0, c.length()); 121 } 122 123 @TestTargets({ 124 @TestTargetNew( 125 level = TestLevel.COMPLETE, 126 method = "setTokenizer", 127 args = {Tokenizer.class} 128 ), 129 @TestTargetNew( 130 level = TestLevel.COMPLETE, 131 method = "enoughToFilter", 132 args = {} 133 ), 134 @TestTargetNew( 135 level = TestLevel.NOT_FEASIBLE, 136 method = "performValidation", 137 args = {} 138 ) 139 }) 140 @UiThreadTest 141 @ToBeFixed(bug = "", explanation = "There will be an endless loop when call performValidation" + 142 " if using CommaTokenizer as the Tokenizer.") testMultiAutoCompleteTextView()143 public void testMultiAutoCompleteTextView() { 144 mMultiAutoCompleteTextView_country.setTokenizer(new CommaTokenizer()); 145 mMultiAutoCompleteTextView_name.setTokenizer(new CommaTokenizer()); 146 147 mMultiAutoCompleteTextView_country.setThreshold(3); 148 mMultiAutoCompleteTextView_name.setThreshold(2); 149 150 assertFalse(mMultiAutoCompleteTextView_country.enoughToFilter()); 151 assertFalse(mMultiAutoCompleteTextView_name.enoughToFilter()); 152 153 setText(mMultiAutoCompleteTextView_country, "Ar"); 154 assertFalse(mMultiAutoCompleteTextView_country.enoughToFilter()); 155 156 setText(mMultiAutoCompleteTextView_country, "Arg"); 157 assertTrue(mMultiAutoCompleteTextView_country.enoughToFilter()); 158 159 setText(mMultiAutoCompleteTextView_country, "Argentina"); 160 assertTrue(mMultiAutoCompleteTextView_country.enoughToFilter()); 161 162 setText(mMultiAutoCompleteTextView_name, "J"); 163 assertFalse(mMultiAutoCompleteTextView_name.enoughToFilter()); 164 165 setText(mMultiAutoCompleteTextView_name, "Ja"); 166 assertTrue(mMultiAutoCompleteTextView_name.enoughToFilter()); 167 168 setText(mMultiAutoCompleteTextView_name, "Jacky"); 169 assertTrue(mMultiAutoCompleteTextView_name.enoughToFilter()); 170 171 MockValidator v = new MockValidator(); 172 v.setValid(true); 173 mMultiAutoCompleteTextView_name.setValidator(v); 174 175 // There will be an endless loop when using CommaTokenizer as the Tokenizer 176 // mMultiAutoCompleteTextView_name.performValidation(); 177 mMultiAutoCompleteTextView_name.setValidator(null); 178 } 179 180 @TestTargetNew( 181 level = TestLevel.COMPLETE, 182 method = "performValidation", 183 args = {} 184 ) 185 @UiThreadTest testPerformValidation()186 public void testPerformValidation() { 187 MockValidator v = new MockValidator(); 188 v.setValid(true); 189 mMultiAutoCompleteTextView_country.setValidator(v); 190 MockTokenizer t = new MockTokenizer(); 191 mMultiAutoCompleteTextView_country.setTokenizer(t); 192 String str = new String("Foo, Android Test, OH"); 193 mMultiAutoCompleteTextView_country.setText(str); 194 mMultiAutoCompleteTextView_country.performValidation(); 195 assertEquals(str, mMultiAutoCompleteTextView_country.getText().toString()); 196 197 v.setValid(false); 198 mMultiAutoCompleteTextView_country.performValidation(); 199 assertEquals(str + ", ", mMultiAutoCompleteTextView_country.getText().toString()); 200 } 201 202 @TestTargets({ 203 @TestTargetNew( 204 level = TestLevel.COMPLETE, 205 method = "performFiltering", 206 args = {java.lang.CharSequence.class, int.class} 207 ), 208 @TestTargetNew( 209 level = TestLevel.COMPLETE, 210 method = "performFiltering", 211 args = {java.lang.CharSequence.class, int.class, int.class, int.class} 212 ) 213 }) 214 @ToBeFixed(bug = "1400249", explanation = "it's hard to do unit test, should be tested by" + 215 " functional test.") testPerformFiltering()216 public void testPerformFiltering() { 217 MyMultiAutoCompleteTextView multiAutoCompleteTextView = 218 new MyMultiAutoCompleteTextView(mActivity); 219 CommaTokenizer t = new CommaTokenizer(); 220 multiAutoCompleteTextView.setTokenizer(t); 221 222 ArrayAdapter<String> adapter = new ArrayAdapter<String>(mActivity, 223 R.layout.simple_dropdown_item_1line); 224 assertNotNull(adapter); 225 226 multiAutoCompleteTextView.setAdapter(adapter); 227 assertNotNull(multiAutoCompleteTextView.getFilter()); 228 229 String text = "Android test."; 230 multiAutoCompleteTextView.setText(text); 231 multiAutoCompleteTextView.setSelection(0, 12); 232 233 multiAutoCompleteTextView.performFiltering(text, KeyEvent.KEYCODE_0); 234 assertNotNull(multiAutoCompleteTextView.getFilter()); 235 236 multiAutoCompleteTextView.performFiltering(text, 0, text.length(), KeyEvent.KEYCODE_E); 237 assertNotNull(multiAutoCompleteTextView.getFilter()); 238 } 239 240 @TestTargetNew( 241 level = TestLevel.COMPLETE, 242 method = "replaceText", 243 args = {java.lang.CharSequence.class} 244 ) testReplaceText()245 public void testReplaceText() { 246 MyMultiAutoCompleteTextView multiAutoCompleteTextView = 247 new MyMultiAutoCompleteTextView(mActivity); 248 CommaTokenizer t = new CommaTokenizer(); 249 multiAutoCompleteTextView.setTokenizer(t); 250 251 String text = "CTS."; 252 multiAutoCompleteTextView.setText(text); 253 assertEquals(text, multiAutoCompleteTextView.getText().toString()); 254 multiAutoCompleteTextView.setSelection(0, text.length()); 255 256 // set the selection range. 257 multiAutoCompleteTextView.replaceText("Android Test."); 258 assertEquals("Android Test., ", multiAutoCompleteTextView.getText().toString()); 259 260 // do not set the selection range. 261 multiAutoCompleteTextView.replaceText("replace test"); 262 assertEquals("Android Test., replace test, ", 263 multiAutoCompleteTextView.getText().toString()); 264 } 265 266 private class MockTokenizer implements Tokenizer { findTokenStart(CharSequence text, int cursor)267 public int findTokenStart(CharSequence text, int cursor) { 268 int i = cursor; 269 while (i > 0 && (text.charAt(i - 1) == ' ' || text.charAt(i - 1) == ',')) { 270 i--; 271 } 272 273 while (i > 0 && text.charAt(i - 1) != ',') { 274 i--; 275 } 276 277 while (i < cursor && text.charAt(i) == ' ') { 278 i++; 279 } 280 281 return i; 282 } 283 findTokenEnd(CharSequence text, int cursor)284 public int findTokenEnd(CharSequence text, int cursor) { 285 int i = cursor; 286 int len = text.length(); 287 288 while (i < len) { 289 if (text.charAt(i) == ',') { 290 return i; 291 } else { 292 i++; 293 } 294 } 295 296 return len; 297 } 298 terminateToken(CharSequence text)299 public CharSequence terminateToken(CharSequence text) { 300 int i = text.length(); 301 302 while (i > 0 && text.charAt(i - 1) == ' ') { 303 i--; 304 } 305 306 if (i > 0 && text.charAt(i - 1) == ',') { 307 return text; 308 } else { 309 if (text instanceof Spanned) { 310 SpannableString sp = new SpannableString(text + ", "); 311 TextUtils.copySpansFrom((Spanned)text, 0, text.length(), Object.class, sp, 0); 312 return sp; 313 } else { 314 return text + ", "; 315 } 316 } 317 } 318 } 319 320 private class MockValidator implements MultiAutoCompleteTextView.Validator { 321 private boolean mIsValid; 322 setValid(boolean b)323 public void setValid(boolean b) { 324 mIsValid = b; 325 } 326 isValid(CharSequence text)327 public boolean isValid(CharSequence text) { 328 return mIsValid; 329 } 330 fixText(CharSequence invalidText)331 public CharSequence fixText(CharSequence invalidText) { 332 return invalidText; 333 } 334 } 335 336 /** 337 * MyMultiAutoCompleteTextView 338 */ 339 private class MyMultiAutoCompleteTextView extends MultiAutoCompleteTextView { MyMultiAutoCompleteTextView(Context c)340 public MyMultiAutoCompleteTextView(Context c) { 341 super(c); 342 } 343 performFiltering(CharSequence text, int keyCode)344 protected void performFiltering(CharSequence text, int keyCode) { 345 super.performFiltering(text, keyCode); 346 } 347 performFiltering(CharSequence text, int start, int end, int keyCode)348 protected void performFiltering(CharSequence text, int start, int end, int keyCode) { 349 super.performFiltering(text, start, end, keyCode); 350 } 351 replaceText(CharSequence text)352 protected void replaceText(CharSequence text) { 353 super.replaceText(text); 354 } 355 getFilter()356 protected Filter getFilter() { 357 return super.getFilter(); 358 } 359 } 360 } 361