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 java.util.ArrayList; 20 import java.util.Comparator; 21 import java.util.List; 22 23 import android.database.DataSetObserver; 24 import android.test.AndroidTestCase; 25 import android.widget.ArrayAdapter; 26 import android.widget.Filter; 27 import android.widget.TextView; 28 29 import com.android.cts.stub.R; 30 31 import dalvik.annotation.TestLevel; 32 import dalvik.annotation.TestTargetClass; 33 import dalvik.annotation.TestTargetNew; 34 import dalvik.annotation.TestTargets; 35 import dalvik.annotation.ToBeFixed; 36 37 @TestTargetClass(ArrayAdapter.class) 38 public class ArrayAdapterTest extends AndroidTestCase { 39 40 private static final int INVALD_ID = -1; 41 private static final String STR1 = "string1"; 42 private static final String STR2 = "string2"; 43 private static final String STR3 = "string3"; 44 45 private ArrayAdapter<String> mArrayAdapter; 46 @Override 47 protected void setUp() throws Exception { 48 super.setUp(); 49 mArrayAdapter = new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line); 50 } 51 52 @TestTargets({ 53 @TestTargetNew( 54 level = TestLevel.COMPLETE, 55 method = "ArrayAdapter", 56 args = {android.content.Context.class, int.class} 57 ), 58 @TestTargetNew( 59 level = TestLevel.COMPLETE, 60 method = "ArrayAdapter", 61 args = {android.content.Context.class, int.class, int.class} 62 ), 63 @TestTargetNew( 64 level = TestLevel.COMPLETE, 65 method = "ArrayAdapter", 66 args = {android.content.Context.class, int.class, int.class, java.util.List.class} 67 ), 68 @TestTargetNew( 69 level = TestLevel.COMPLETE, 70 method = "ArrayAdapter", 71 args = {android.content.Context.class, int.class, java.util.List.class} 72 ), 73 @TestTargetNew( 74 level = TestLevel.COMPLETE, 75 method = "ArrayAdapter", 76 args = {android.content.Context.class, int.class, int.class, java.lang.Object[].class} 77 ), 78 @TestTargetNew( 79 level = TestLevel.COMPLETE, 80 method = "ArrayAdapter", 81 args = {android.content.Context.class, int.class, java.lang.Object[].class} 82 ) 83 }) 84 @ToBeFixed(bug = "1695243", explanation = "should add NullPointerException @throws" 85 + " clause into javadoc.") 86 public void testConstructor() { 87 88 new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line); 89 new ArrayAdapter<String>(mContext, INVALD_ID);// invalid resource id 90 91 new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, R.id.text1); 92 new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, INVALD_ID); 93 94 new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, 95 new String[] {"str1", "str2"}); 96 97 new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, R.id.text1, 98 new String[] {"str1", "str2"}); 99 100 List<String> list = new ArrayList<String>(); 101 list.add(STR1); 102 list.add(STR2); 103 104 new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, list); 105 106 new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, R.id.text1, list); 107 108 // invalid input 109 try { 110 new ArrayAdapter<String>(null, R.layout.simple_dropdown_item_1line); 111 fail("should throw NullPointerException"); 112 } catch (NullPointerException e) { 113 // expected exception 114 } 115 } 116 117 @TestTargets({ 118 @TestTargetNew( 119 level = TestLevel.COMPLETE, 120 method = "setNotifyOnChange", 121 args = {boolean.class} 122 ), 123 @TestTargetNew( 124 level = TestLevel.COMPLETE, 125 method = "notifyDataSetChanged", 126 args = {} 127 ), 128 @TestTargetNew( 129 level = TestLevel.COMPLETE, 130 method = "add", 131 args = {java.lang.Object.class} 132 ), 133 @TestTargetNew( 134 level = TestLevel.COMPLETE, 135 method = "clear", 136 args = {} 137 ) 138 139 }) 140 public void testDataChangeEvent() { 141 final MockDataSetObserver mockDataSetObserver = new MockDataSetObserver(); 142 mArrayAdapter.registerDataSetObserver(mockDataSetObserver); 143 144 // enable automatically notifying. 145 mArrayAdapter.setNotifyOnChange(true); 146 assertEquals(0, mockDataSetObserver.getCalledOnChangedCount()); 147 mArrayAdapter.add(STR1); 148 assertEquals(1, mArrayAdapter.getCount()); 149 assertEquals(1, mockDataSetObserver.getCalledOnChangedCount()); 150 mArrayAdapter.add(STR2); 151 assertEquals(2, mArrayAdapter.getCount()); 152 assertEquals(2, mockDataSetObserver.getCalledOnChangedCount()); 153 154 // reset data 155 mArrayAdapter.clear(); 156 // clear notify changed 157 assertEquals(3, mockDataSetObserver.getCalledOnChangedCount()); 158 assertEquals(0, mArrayAdapter.getCount()); 159 // if empty before, clear also notify changed 160 mArrayAdapter.clear(); 161 assertEquals(4, mockDataSetObserver.getCalledOnChangedCount()); 162 mockDataSetObserver.clearCount(); 163 assertEquals(0, mockDataSetObserver.getCalledOnChangedCount()); 164 165 // disable auto notify 166 mArrayAdapter.setNotifyOnChange(false); 167 168 mArrayAdapter.add(STR3); 169 assertEquals(1, mArrayAdapter.getCount()); 170 assertEquals(0, mockDataSetObserver.getCalledOnChangedCount()); 171 172 // manually notify 173 mArrayAdapter.notifyDataSetChanged(); 174 assertEquals(1, mockDataSetObserver.getCalledOnChangedCount()); 175 // no data changed, but force notify 176 mArrayAdapter.notifyDataSetChanged(); 177 assertEquals(2, mockDataSetObserver.getCalledOnChangedCount()); 178 // once called notify, auto notify enabled 179 mArrayAdapter.add(STR3); 180 assertEquals(3, mockDataSetObserver.getCalledOnChangedCount()); 181 } 182 183 @TestTargets({ 184 @TestTargetNew( 185 level = TestLevel.COMPLETE, 186 method = "getContext", 187 args = {} 188 ), 189 @TestTargetNew( 190 level = TestLevel.COMPLETE, 191 method = "getCount", 192 args = {} 193 ), 194 @TestTargetNew( 195 level = TestLevel.COMPLETE, 196 method = "getView", 197 args = {int.class, android.view.View.class, android.view.ViewGroup.class} 198 ), 199 @TestTargetNew( 200 level = TestLevel.COMPLETE, 201 method = "getDropDownView", 202 args = {int.class, android.view.View.class, android.view.ViewGroup.class} 203 ) 204 }) 205 @ToBeFixed(bug = "1695243", explanation = "should add NullPointerException @throws" 206 + " clause into javadoc.") 207 public void testAccessView() { 208 final TextView textView = new TextView(mContext); 209 textView.setText(STR3); 210 211 assertNotNull(mArrayAdapter.getContext()); 212 213 assertEquals(0, mArrayAdapter.getCount()); 214 215 mArrayAdapter.add(STR1); 216 mArrayAdapter.add(STR2); 217 mArrayAdapter.add(STR3); 218 219 assertEquals(3, mArrayAdapter.getCount()); 220 221 assertEquals(STR1, ((TextView) mArrayAdapter.getView(0, null, null)).getText()); 222 assertEquals(STR2, ((TextView) mArrayAdapter.getView(1, null, null)).getText()); 223 assertEquals(STR3, ((TextView) mArrayAdapter.getDropDownView(2, null, null)).getText()); 224 225 assertEquals(STR3, textView.getText()); 226 assertSame(textView, mArrayAdapter.getView(0, textView, null)); 227 assertSame(textView, mArrayAdapter.getDropDownView(0, textView, null)); 228 assertEquals(STR1, textView.getText()); 229 230 try { 231 assertEquals(textView, mArrayAdapter.getView(-1, textView, null)); 232 fail("should throw IndexOutOfBoundsException"); 233 } catch (IndexOutOfBoundsException e) { 234 } 235 236 try { 237 assertEquals(textView, mArrayAdapter.getDropDownView(-1, textView, null)); 238 fail("should throw IndexOutOfBoundsException"); 239 } catch (IndexOutOfBoundsException e) { 240 } 241 242 try { 243 assertEquals(textView, 244 mArrayAdapter.getView(mArrayAdapter.getCount(), textView, null)); 245 fail("should throw IndexOutOfBoundsException"); 246 } catch (IndexOutOfBoundsException e) { 247 } 248 249 try { 250 assertEquals(textView, 251 mArrayAdapter.getDropDownView(mArrayAdapter.getCount(), textView, null)); 252 fail("should throw IndexOutOfBoundsException"); 253 } catch (IndexOutOfBoundsException e) { 254 } 255 } 256 257 @TestTargetNew( 258 level = TestLevel.COMPLETE, 259 method = "getFilter", 260 args = {} 261 ) 262 @ToBeFixed(bug = "", explanation = "Can not check the filter's filting result.") 263 public void testGetFilter() { 264 Filter filter = mArrayAdapter.getFilter(); 265 266 assertNotNull(mArrayAdapter.getFilter()); 267 assertSame(filter, mArrayAdapter.getFilter()); 268 } 269 270 /** 271 * just simple change the resource id from which the drop view inflate from 272 * we set a xml that not contain a textview, so exception should throw to lete us know 273 * sucessfully change the dropdown xml, but should not affect the normal view by getview 274 */ 275 @TestTargetNew( 276 level = TestLevel.COMPLETE, 277 method = "setDropDownViewResource", 278 args = {int.class} 279 ) 280 public void testSetDropDownViewResouce() { 281 mArrayAdapter.add(STR1); 282 283 mArrayAdapter.getDropDownView(0, null, null); 284 285 mArrayAdapter.setDropDownViewResource(R.layout.tabhost_layout); 286 // getview is ok 287 mArrayAdapter.getView(0, null, null); 288 // getDropDownView error for it changed 289 try { 290 mArrayAdapter.getDropDownView(0, null, null); 291 fail("should throw IllegalStateException"); 292 } catch (IllegalStateException e) { 293 // expected exception 294 } 295 296 mArrayAdapter.setDropDownViewResource(INVALD_ID); 297 } 298 299 /** 300 * insert the item to the specific position, notify data changed 301 * check -1, normal, > count 302 */ 303 @TestTargets({ 304 @TestTargetNew( 305 level = TestLevel.COMPLETE, 306 method = "insert", 307 args = {java.lang.Object.class, int.class} 308 ) 309 }) 310 public void testInsert() { 311 mArrayAdapter.setNotifyOnChange(true); 312 final MockDataSetObserver mockDataSetObserver = new MockDataSetObserver(); 313 mArrayAdapter.registerDataSetObserver(mockDataSetObserver); 314 315 mArrayAdapter.insert(STR1, 0); 316 assertEquals(1, mArrayAdapter.getCount()); 317 assertEquals(0, mArrayAdapter.getPosition(STR1)); 318 assertEquals(1, mockDataSetObserver.getCalledOnChangedCount()); 319 320 mArrayAdapter.insert(STR2, 0); 321 assertEquals(2, mArrayAdapter.getCount()); 322 assertEquals(1, mArrayAdapter.getPosition(STR1)); 323 assertEquals(0, mArrayAdapter.getPosition(STR2)); 324 325 mArrayAdapter.insert(STR3, mArrayAdapter.getCount()); 326 assertEquals(mArrayAdapter.getCount() - 1, mArrayAdapter.getPosition(STR3)); 327 328 mArrayAdapter.insert(null, 0); 329 assertEquals(0, mArrayAdapter.getPosition(null)); 330 331 try { 332 mArrayAdapter.insert(STR1, -1); 333 fail("should throw IndexOutOfBoundsException"); 334 } catch (IndexOutOfBoundsException e) { 335 // expected exception 336 } 337 338 try { 339 mArrayAdapter.insert(STR1, mArrayAdapter.getCount() + 1); 340 fail("should throw IndexOutOfBoundsException"); 341 } catch (IndexOutOfBoundsException e) { 342 // expected exception 343 } 344 } 345 346 /** 347 * return the given position obj 348 * test range: -1, normal, > count 349 */ 350 @TestTargetNew( 351 level = TestLevel.COMPLETE, 352 method = "getItem", 353 args = {int.class} 354 ) 355 public void testGetItem() { 356 mArrayAdapter.add(STR1); 357 mArrayAdapter.add(STR2); 358 mArrayAdapter.add(STR3); 359 360 assertSame(STR1, mArrayAdapter.getItem(0)); 361 assertSame(STR2, mArrayAdapter.getItem(1)); 362 assertSame(STR3, mArrayAdapter.getItem(2)); 363 364 // test invalid input 365 try { 366 mArrayAdapter.getItem(-1); 367 fail("should throw IndexOutOfBoundsException"); 368 } catch (IndexOutOfBoundsException e) { 369 // expected exception 370 } 371 372 try { 373 mArrayAdapter.getItem(mArrayAdapter.getCount()); 374 fail("should throw IndexOutOfBoundsException"); 375 } catch (IndexOutOfBoundsException e) { 376 // expected exception 377 } 378 } 379 380 /** 381 * just return the given position 382 */ 383 @TestTargetNew( 384 level = TestLevel.COMPLETE, 385 method = "getItemId", 386 args = {int.class} 387 ) 388 public void testGetItemId() { 389 mArrayAdapter.add(STR1); 390 mArrayAdapter.add(STR2); 391 mArrayAdapter.add(STR3); 392 393 assertEquals(0, mArrayAdapter.getItemId(0)); 394 assertEquals(1, mArrayAdapter.getItemId(1)); 395 assertEquals(2, mArrayAdapter.getItemId(2)); 396 397 // test invalid input 398 assertEquals(-1, mArrayAdapter.getItemId(-1)); 399 assertEquals(mArrayAdapter.getCount(), 400 mArrayAdapter.getItemId(mArrayAdapter.getCount())); 401 } 402 403 /* 404 * return the obj position that in the array, if there are same objs, return the first one 405 */ 406 @TestTargetNew( 407 level = TestLevel.COMPLETE, 408 method = "getPosition", 409 args = {java.lang.Object.class} 410 ) 411 public void testGetPosition() { 412 mArrayAdapter.add(STR1); 413 mArrayAdapter.add(STR2); 414 mArrayAdapter.add(STR1); 415 416 assertEquals(0, mArrayAdapter.getPosition(STR1)); 417 assertEquals(1, mArrayAdapter.getPosition(STR2)); 418 // return the first one if same obj exsit 419 assertEquals(0, mArrayAdapter.getPosition(STR1)); 420 421 assertEquals(-1, mArrayAdapter.getPosition(STR3)); 422 423 // test invalid input 424 assertEquals(-1, mArrayAdapter.getPosition(null)); 425 } 426 427 /** 428 * Removes the specified object from the array. notify data changed 429 * remove first one if duplicated string in the array 430 */ 431 @TestTargetNew( 432 level = TestLevel.COMPLETE, 433 method = "remove", 434 args = {java.lang.Object.class} 435 ) 436 public void testRemove() { 437 final MockDataSetObserver mockDataSetObserver = new MockDataSetObserver(); 438 mArrayAdapter.registerDataSetObserver(mockDataSetObserver); 439 mArrayAdapter.setNotifyOnChange(true); 440 441 // remove the not exist one 442 assertEquals(0, mArrayAdapter.getCount()); 443 assertEquals(0, mockDataSetObserver.getCalledOnChangedCount()); 444 // remove the item not exist also notify change 445 mArrayAdapter.remove(STR1); 446 assertEquals(1, mockDataSetObserver.getCalledOnChangedCount()); 447 448 mArrayAdapter.add(STR1); 449 mArrayAdapter.add(STR2); 450 mArrayAdapter.add(STR3); 451 mArrayAdapter.add(STR2); 452 mockDataSetObserver.clearCount(); 453 assertEquals(0, mockDataSetObserver.getCalledOnChangedCount()); 454 assertEquals(4, mArrayAdapter.getCount()); 455 456 mArrayAdapter.remove(STR1); 457 assertEquals(3, mArrayAdapter.getCount()); 458 assertEquals(-1, mArrayAdapter.getPosition(STR1)); 459 assertEquals(0, mArrayAdapter.getPosition(STR2)); 460 assertEquals(1, mArrayAdapter.getPosition(STR3)); 461 assertEquals(1, mockDataSetObserver.getCalledOnChangedCount()); 462 463 mArrayAdapter.remove(STR2); 464 assertEquals(2, mArrayAdapter.getCount()); 465 // remove the first one if dumplicated 466 assertEquals(1, mArrayAdapter.getPosition(STR2)); 467 assertEquals(0, mArrayAdapter.getPosition(STR3)); 468 469 mArrayAdapter.remove(STR2); 470 assertEquals(1, mArrayAdapter.getCount()); 471 assertEquals(-1, mArrayAdapter.getPosition(STR2)); 472 assertEquals(0, mArrayAdapter.getPosition(STR3)); 473 } 474 475 /* 476 * Creates a new ArrayAdapter from external resources. The content of the array is 477 * obtained through {@link android.content.res.Resources#getTextArray(int)}. 478 */ 479 @TestTargetNew( 480 level = TestLevel.COMPLETE, 481 method = "createFromResource", 482 args = {android.content.Context.class, int.class, int.class} 483 ) 484 @ToBeFixed(bug = "1695243", explanation = "should add NullPointerException @throws" 485 + " clause into javadoc.") 486 public void testCreateFromResource() { 487 ArrayAdapter.createFromResource(mContext, R.array.string, R.layout.simple_spinner_item); 488 489 // invalid input 490 try { 491 ArrayAdapter.createFromResource(null, R.array.string, R.layout.simple_spinner_item); 492 fail("should throw NullPointerException"); 493 } catch (NullPointerException e) { 494 // expected exception 495 } 496 497 try { 498 ArrayAdapter.createFromResource(mContext, INVALD_ID, R.layout.simple_spinner_item); 499 fail("should throw NullPointerException"); 500 } catch (NullPointerException e) { 501 // expected exception 502 } 503 504 ArrayAdapter.createFromResource(mContext, R.array.string, INVALD_ID); 505 } 506 507 @TestTargetNew( 508 level = TestLevel.COMPLETE, 509 method = "createFromResource", 510 args = {android.content.Context.class, int.class, int.class} 511 ) 512 public void testSort() { 513 final MockDataSetObserver mockDataSetObserver = new MockDataSetObserver(); 514 mArrayAdapter.registerDataSetObserver(mockDataSetObserver); 515 mArrayAdapter.setNotifyOnChange(true); 516 assertEquals(0, mockDataSetObserver.getCalledOnChangedCount()); 517 518 mArrayAdapter.sort( new Comparator<String>() { 519 public int compare(String o1, String o2) { 520 return 0; 521 } 522 }); 523 assertEquals(1, mockDataSetObserver.getCalledOnChangedCount()); 524 525 mArrayAdapter.sort(null); 526 assertEquals(2, mockDataSetObserver.getCalledOnChangedCount()); 527 } 528 529 private static class MockDataSetObserver extends DataSetObserver { 530 531 private int mCalledOnChangedCount; 532 private int mOnCalledInvalidatedCount; 533 534 public MockDataSetObserver() { 535 clearCount(); 536 } 537 538 public int getCalledOnChangedCount() { 539 return mCalledOnChangedCount; 540 } 541 542 public int getCalledOnInvalidatedCount() { 543 return mOnCalledInvalidatedCount; 544 } 545 546 public void clearCount() { 547 mCalledOnChangedCount = 0; 548 mOnCalledInvalidatedCount = 0; 549 } 550 551 public void onChanged() { 552 mCalledOnChangedCount++; 553 } 554 555 public void onInvalidated() { 556 mOnCalledInvalidatedCount++; 557 } 558 } 559 } 560