blob: 4350103ae6fef167da21b3857d88f5760fcdea90 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.widget.cts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.database.DataSetObserver;
import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.TextView;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ArrayAdapterTest {
private static final int INVALID_ID = -1;
private static final String STR1 = "string1";
private static final String STR2 = "string2";
private static final String STR3 = "string3";
private ArrayAdapter<String> mArrayAdapter;
private Context mContext;
@Rule
public ActivityTestRule<CtsActivity> mActivityRule =
new ActivityTestRule<>(CtsActivity.class);
@Before
public void setup() {
mContext = InstrumentationRegistry.getTargetContext();
mArrayAdapter = new ArrayAdapter<>(mContext, R.layout.simple_dropdown_item_1line);
}
@Test
public void testConstructor() {
new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line);
new ArrayAdapter<String>(mContext, INVALID_ID); // invalid resource id
new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, R.id.text1);
new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, INVALID_ID);
new ArrayAdapter<>(mContext, R.layout.simple_dropdown_item_1line,
new String[] {"str1", "str2"});
new ArrayAdapter<>(mContext, R.layout.simple_dropdown_item_1line, R.id.text1,
new String[] {"str1", "str2"});
List<String> list = new ArrayList<>();
list.add(STR1);
list.add(STR2);
new ArrayAdapter<>(mContext, R.layout.simple_dropdown_item_1line, list);
new ArrayAdapter<>(mContext, R.layout.simple_dropdown_item_1line, R.id.text1, list);
}
@Test(expected=NullPointerException.class)
public void testConstructorWithNullContext() {
new ArrayAdapter<String>(null, R.layout.simple_dropdown_item_1line);
}
@Test
public void testDataChangeEvent() {
final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
// enable automatically notifying.
mArrayAdapter.setNotifyOnChange(true);
verifyZeroInteractions(mockDataSetObserver);
mArrayAdapter.add(STR1);
assertEquals(1, mArrayAdapter.getCount());
verify(mockDataSetObserver, times(1)).onChanged();
mArrayAdapter.add(STR2);
assertEquals(2, mArrayAdapter.getCount());
verify(mockDataSetObserver, times(2)).onChanged();
// reset data
mArrayAdapter.clear();
// clear notify changed
verify(mockDataSetObserver, times(3)).onChanged();
assertEquals(0, mArrayAdapter.getCount());
// if empty before, clear also notify changed
mArrayAdapter.clear();
verify(mockDataSetObserver, times(4)).onChanged();
reset(mockDataSetObserver);
// disable auto notify
mArrayAdapter.setNotifyOnChange(false);
mArrayAdapter.add(STR3);
assertEquals(1, mArrayAdapter.getCount());
verifyZeroInteractions(mockDataSetObserver);
// manually notify
mArrayAdapter.notifyDataSetChanged();
verify(mockDataSetObserver, times(1)).onChanged();
// no data changed, but force notify
mArrayAdapter.notifyDataSetChanged();
verify(mockDataSetObserver, times(2)).onChanged();
// once called notify, auto notify enabled
mArrayAdapter.add(STR3);
verify(mockDataSetObserver, times(3)).onChanged();
}
@UiThreadTest
@Test
public void testAccessView() {
final TextView textView = new TextView(mContext);
textView.setText(STR3);
assertNotNull(mArrayAdapter.getContext());
assertEquals(0, mArrayAdapter.getCount());
mArrayAdapter.add(STR1);
mArrayAdapter.add(STR2);
mArrayAdapter.add(STR3);
assertEquals(3, mArrayAdapter.getCount());
assertEquals(STR1, ((TextView) mArrayAdapter.getView(0, null, null)).getText());
assertEquals(STR2, ((TextView) mArrayAdapter.getView(1, null, null)).getText());
assertEquals(STR3, ((TextView) mArrayAdapter.getDropDownView(2, null, null)).getText());
assertEquals(STR3, textView.getText());
assertSame(textView, mArrayAdapter.getView(0, textView, null));
assertSame(textView, mArrayAdapter.getDropDownView(0, textView, null));
assertEquals(STR1, textView.getText());
}
@UiThreadTest
@Test(expected=IndexOutOfBoundsException.class)
public void testGetViewOutOfBoundsLow() {
final TextView textView = new TextView(mContext);
mArrayAdapter.getView(-1, textView, null);
}
@UiThreadTest
@Test(expected=IndexOutOfBoundsException.class)
public void testDropDownGetViewOutOfBoundsLow() {
final TextView textView = new TextView(mContext);
mArrayAdapter.getDropDownView(-1, textView, null);
}
@UiThreadTest
@Test(expected=IndexOutOfBoundsException.class)
public void testGetViewOutOfBoundsHigh() {
final TextView textView = new TextView(mContext);
mArrayAdapter.getView(mArrayAdapter.getCount(), textView, null);
}
@UiThreadTest
@Test(expected=IndexOutOfBoundsException.class)
public void testDropDownGetViewOutOfBoundsHigh() {
final TextView textView = new TextView(mContext);
mArrayAdapter.getDropDownView(mArrayAdapter.getCount(), textView, null);
}
@Test
public void testGetFilter() throws Throwable {
mActivityRule.runOnUiThread(() -> {
Filter filter = mArrayAdapter.getFilter();
assertNotNull(mArrayAdapter.getFilter());
assertSame(filter, mArrayAdapter.getFilter());
});
}
/**
* Just simple change the resource id from which the drop view inflate from
* we set a xml that not contain a textview, so exception should throw to lete us know
* sucessfully change the dropdown xml, but should not affect the normal view by getview
*/
@UiThreadTest
@Test
public void testSetDropDownViewResource() {
mArrayAdapter.add(STR1);
mArrayAdapter.getDropDownView(0, null, null);
mArrayAdapter.setDropDownViewResource(R.layout.tabhost_layout);
// getview is ok
mArrayAdapter.getView(0, null, null);
mArrayAdapter.setDropDownViewResource(INVALID_ID);
}
@UiThreadTest
@Test(expected=IllegalStateException.class)
public void testSetDropDownViewResourceIllegal() {
mArrayAdapter.add(STR1);
mArrayAdapter.setDropDownViewResource(R.layout.tabhost_layout);
mArrayAdapter.getDropDownView(0, null, null);
}
@Test
public void testAccessDropDownViewTheme() {
Theme theme = mContext.getResources().newTheme();
mArrayAdapter.setDropDownViewTheme(theme);
assertSame(theme, mArrayAdapter.getDropDownViewTheme());
}
/**
* insert the item to the specific position, notify data changed
* check -1, normal, > count
*/
@Test
public void testInsert() {
mArrayAdapter.setNotifyOnChange(true);
final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
mArrayAdapter.insert(STR1, 0);
assertEquals(1, mArrayAdapter.getCount());
assertEquals(0, mArrayAdapter.getPosition(STR1));
verify(mockDataSetObserver, times(1)).onChanged();
mArrayAdapter.insert(STR2, 0);
assertEquals(2, mArrayAdapter.getCount());
assertEquals(1, mArrayAdapter.getPosition(STR1));
assertEquals(0, mArrayAdapter.getPosition(STR2));
mArrayAdapter.insert(STR3, mArrayAdapter.getCount());
assertEquals(mArrayAdapter.getCount() - 1, mArrayAdapter.getPosition(STR3));
mArrayAdapter.insert(null, 0);
assertEquals(0, mArrayAdapter.getPosition(null));
}
@Test(expected=IndexOutOfBoundsException.class)
public void testInsertOutOfBoundsLow() {
mArrayAdapter.insert(STR1, 0);
mArrayAdapter.insert(STR2, 0);
mArrayAdapter.insert(null, 0);
mArrayAdapter.insert(STR1, -1);
}
@Test(expected=IndexOutOfBoundsException.class)
public void testInsertOutOfBoundsHigh() {
mArrayAdapter.insert(STR1, 0);
mArrayAdapter.insert(STR2, 0);
mArrayAdapter.insert(null, 0);
mArrayAdapter.insert(STR1, mArrayAdapter.getCount() + 1);
}
/**
* return the given position obj
* test range: -1, normal, > count
*/
@Test
public void testGetItem() {
mArrayAdapter.add(STR1);
mArrayAdapter.add(STR2);
mArrayAdapter.add(STR3);
assertSame(STR1, mArrayAdapter.getItem(0));
assertSame(STR2, mArrayAdapter.getItem(1));
assertSame(STR3, mArrayAdapter.getItem(2));
}
@Test(expected=IndexOutOfBoundsException.class)
public void testGetItemOutOfBoundsLow() {
mArrayAdapter.add(STR1);
mArrayAdapter.add(STR2);
mArrayAdapter.add(STR3);
mArrayAdapter.getItem(-1);
}
@Test(expected=IndexOutOfBoundsException.class)
public void testGetItemOutOfBoundsHigh() {
mArrayAdapter.add(STR1);
mArrayAdapter.add(STR2);
mArrayAdapter.add(STR3);
mArrayAdapter.getItem(mArrayAdapter.getCount());
}
/**
* just return the given position
*/
@Test
public void testGetItemId() {
mArrayAdapter.add(STR1);
mArrayAdapter.add(STR2);
mArrayAdapter.add(STR3);
assertEquals(0, mArrayAdapter.getItemId(0));
assertEquals(1, mArrayAdapter.getItemId(1));
assertEquals(2, mArrayAdapter.getItemId(2));
// test invalid input
assertEquals(-1, mArrayAdapter.getItemId(-1));
assertEquals(mArrayAdapter.getCount(), mArrayAdapter.getItemId(mArrayAdapter.getCount()));
}
/*
* return the obj position that in the array, if there are same objs, return the first one
*/
@Test
public void testGetPosition() {
mArrayAdapter.add(STR1);
mArrayAdapter.add(STR2);
mArrayAdapter.add(STR1);
assertEquals(0, mArrayAdapter.getPosition(STR1));
assertEquals(1, mArrayAdapter.getPosition(STR2));
// return the first one if same obj exsit
assertEquals(0, mArrayAdapter.getPosition(STR1));
assertEquals(-1, mArrayAdapter.getPosition(STR3));
// test invalid input
assertEquals(-1, mArrayAdapter.getPosition(null));
}
/**
* Removes the specified object from the array. notify data changed
* remove first one if duplicated string in the array
*/
@Test
public void testRemove() {
final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
mArrayAdapter.setNotifyOnChange(true);
// remove the not exist one
assertEquals(0, mArrayAdapter.getCount());
verifyZeroInteractions(mockDataSetObserver);
// remove the item not exist also notify change
mArrayAdapter.remove(STR1);
verify(mockDataSetObserver, times(1)).onChanged();
mArrayAdapter.add(STR1);
mArrayAdapter.add(STR2);
mArrayAdapter.add(STR3);
mArrayAdapter.add(STR2);
reset(mockDataSetObserver);
assertEquals(4, mArrayAdapter.getCount());
mArrayAdapter.remove(STR1);
assertEquals(3, mArrayAdapter.getCount());
assertEquals(-1, mArrayAdapter.getPosition(STR1));
assertEquals(0, mArrayAdapter.getPosition(STR2));
assertEquals(1, mArrayAdapter.getPosition(STR3));
verify(mockDataSetObserver, times(1)).onChanged();
mArrayAdapter.remove(STR2);
assertEquals(2, mArrayAdapter.getCount());
// remove the first one if duplicated
assertEquals(1, mArrayAdapter.getPosition(STR2));
assertEquals(0, mArrayAdapter.getPosition(STR3));
mArrayAdapter.remove(STR2);
assertEquals(1, mArrayAdapter.getCount());
assertEquals(-1, mArrayAdapter.getPosition(STR2));
assertEquals(0, mArrayAdapter.getPosition(STR3));
}
/*
* Creates a new ArrayAdapter from external resources. The content of the array is
* obtained through {@link android.content.res.Resources#getTextArray(int)}.
*/
@Test
public void testCreateFromResource() {
final ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
R.array.string, R.layout.simple_spinner_item);
final CharSequence[] staticOptions = adapter.getAutofillOptions();
assertEquals(3, staticOptions.length);
assertEquals("Test String 1", staticOptions[0]);
assertEquals("Test String 2", staticOptions[1]);
assertEquals("Test String 3", staticOptions[2]);
// Make sure values set dynamically wins.
adapter.setAutofillOptions("Dynamic", "am I");
final CharSequence[] dynamicOptions = adapter.getAutofillOptions();
assertEquals(2, dynamicOptions.length);
assertEquals("Dynamic", dynamicOptions[0]);
assertEquals("am I", dynamicOptions[1]);
ArrayAdapter.createFromResource(mContext, R.array.string, INVALID_ID);
}
@Test(expected=NullPointerException.class)
public void testCreateFromResourceWithNullContext() {
ArrayAdapter.createFromResource(null, R.array.string, R.layout.simple_spinner_item);
}
@Test(expected=Resources.NotFoundException.class)
public void testCreateFromResourceWithInvalidId() {
ArrayAdapter.createFromResource(mContext, INVALID_ID, R.layout.simple_spinner_item);
}
@Test
public void testSort() {
final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
mArrayAdapter.setNotifyOnChange(true);
verifyZeroInteractions(mockDataSetObserver);
mArrayAdapter.sort((String o1, String o2) -> 0);
verify(mockDataSetObserver, times(1)).onChanged();
mArrayAdapter.sort(null);
verify(mockDataSetObserver, times(2)).onChanged();
}
/**
* insert multiple items via add, notify data changed
* check count and content
*/
@Test
public void testAdd() {
mArrayAdapter.setNotifyOnChange(true);
final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
mArrayAdapter.clear();
assertEquals(mArrayAdapter.getCount(), 0);
mArrayAdapter.add("testing");
mArrayAdapter.add("android");
assertEquals(mArrayAdapter.getCount(), 2);
assertEquals(mArrayAdapter.getItem(0), "testing");
assertEquals(mArrayAdapter.getItem(1), "android");
}
/**
* insert multiple items via addAll, notify data changed
* check count and content
*/
@Test
public void testAddAllCollection() {
mArrayAdapter.setNotifyOnChange(true);
final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
List<String> list = new ArrayList<>();
list.add("");
list.add("hello");
list.add("android");
list.add("!");
mArrayAdapter.clear();
assertEquals(mArrayAdapter.getCount(), 0);
mArrayAdapter.addAll(list);
assertEquals(mArrayAdapter.getCount(), list.size());
assertEquals(mArrayAdapter.getItem(0), list.get(0));
assertEquals(mArrayAdapter.getItem(1), list.get(1));
assertEquals(mArrayAdapter.getItem(2), list.get(2));
assertEquals(mArrayAdapter.getItem(3), list.get(3));
}
/**
* insert multiple items via addAll, notify data changed
* check count and content
*/
@Test
public void testAddAllParams() {
mArrayAdapter.setNotifyOnChange(true);
final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
mArrayAdapter.clear();
assertEquals(mArrayAdapter.getCount(), 0);
mArrayAdapter.addAll("this", "is", "a", "unit", "test");
assertEquals(mArrayAdapter.getCount(), 5);
assertEquals(mArrayAdapter.getItem(0), "this");
assertEquals(mArrayAdapter.getItem(1), "is");
assertEquals(mArrayAdapter.getItem(2), "a");
assertEquals(mArrayAdapter.getItem(3), "unit");
assertEquals(mArrayAdapter.getItem(4), "test");
}
}