Loading tests/src/com/android/contacts/database/SimContactDaoTests.java +15 −134 Original line number Diff line number Diff line Loading @@ -20,8 +20,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.OperationApplicationException; import android.database.Cursor; import android.database.CursorWrapper; import android.database.DatabaseUtils; import android.os.RemoteException; import android.provider.ContactsContract; import android.provider.ContactsContract.CommonDataKinds.Email; Loading @@ -43,13 +41,12 @@ import com.android.contacts.model.SimContact; import com.android.contacts.model.account.AccountWithDataSet; import com.android.contacts.common.test.mocks.MockContentProvider; import com.android.contacts.tests.AccountsTestHelper; import com.android.contacts.tests.ContactsMatchers; import com.android.contacts.tests.SimContactsTestHelper; import com.android.contacts.tests.StringableCursor; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.Matchers; import org.junit.After; import org.junit.AfterClass; Loading @@ -68,6 +65,10 @@ import java.util.Random; import java.util.Set; import static android.os.Build.VERSION_CODES; import static com.android.contacts.tests.ContactsMatchers.DataCursor.hasEmail; import static com.android.contacts.tests.ContactsMatchers.DataCursor.hasName; import static com.android.contacts.tests.ContactsMatchers.DataCursor.hasPhone; import static com.android.contacts.tests.ContactsMatchers.isSimContactWithNameAndPhone; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; Loading Loading @@ -127,19 +128,19 @@ public class SimContactDaoTests { ), mAccount); Cursor cursor = queryContactWithName("Test One"); assertThat(cursor, hasCount(2)); assertThat(cursor, ContactsMatchers.hasCount(2)); assertThat(cursor, hasName("Test One")); assertThat(cursor, hasPhone("15095550101")); cursor.close(); cursor = queryContactWithName("Test Two"); assertThat(cursor, hasCount(2)); assertThat(cursor, ContactsMatchers.hasCount(2)); assertThat(cursor, hasName("Test Two")); assertThat(cursor, hasPhone("15095550102")); cursor.close(); cursor = queryContactWithName("Test Three"); assertThat(cursor, hasCount(4)); assertThat(cursor, ContactsMatchers.hasCount(4)); assertThat(cursor, hasName("Test Three")); assertThat(cursor, hasPhone("15095550103")); assertThat(cursor, allOf(hasEmail("user@example.com"), hasEmail("user2@example.com"))); Loading @@ -156,7 +157,7 @@ public class SimContactDaoTests { Cursor cursor = queryAllDataInAccount(); assertThat(cursor, hasCount(1)); assertThat(cursor, ContactsMatchers.hasCount(1)); assertThat(cursor, hasName("Test importJustName")); cursor.close(); } Loading @@ -171,7 +172,7 @@ public class SimContactDaoTests { Cursor cursor = queryAllDataInAccount(); assertThat(cursor, hasCount(1)); assertThat(cursor, ContactsMatchers.hasCount(1)); assertThat(cursor, hasPhone("15095550111")); cursor.close(); } Loading @@ -190,11 +191,11 @@ public class SimContactDaoTests { ), mAccount); final Cursor contactsCursor = queryAllRawContactsInAccount(); assertThat(contactsCursor, hasCount(1)); assertThat(contactsCursor, ContactsMatchers.hasCount(1)); contactsCursor.close(); final Cursor dataCursor = queryAllDataInAccount(); assertThat(dataCursor, hasCount(1)); assertThat(dataCursor, ContactsMatchers.hasCount(1)); dataCursor.close(); } Loading @@ -218,12 +219,12 @@ public class SimContactDaoTests { sut.importContacts(contacts, mAccount); final Cursor contactsCursor = queryAllRawContactsInAccount(); assertThat(contactsCursor, hasCount(MAX_SIM_CONTACTS)); assertThat(contactsCursor, ContactsMatchers.hasCount(MAX_SIM_CONTACTS)); contactsCursor.close(); final Cursor dataCursor = queryAllDataInAccount(); // Each contact has one data row for each of name, phone and email assertThat(dataCursor, hasCount(MAX_SIM_CONTACTS * 3)); assertThat(dataCursor, ContactsMatchers.hasCount(MAX_SIM_CONTACTS * 3)); dataCursor.close(); } Loading Loading @@ -740,126 +741,6 @@ public class SimContactDaoTests { } } private static Matcher<SimContact> isSimContactWithNameAndPhone(final String name, final String phone) { return new BaseMatcher<SimContact>() { @Override public boolean matches(Object o) { if (!(o instanceof SimContact)) return false; SimContact other = (SimContact) o; return name.equals(other.getName()) && phone.equals(other.getPhone()); } @Override public void describeTo(Description description) { description.appendText("SimContact with name=" + name + " and phone=" + phone); } }; } private static Matcher<Cursor> hasCount(final int count) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; return ((Cursor)o).getCount() == count; } @Override public void describeTo(Description description) { description.appendText("Cursor with " + count + " rows"); } }; } private static Matcher<Cursor> hasMimeType(String type) { return hasValueForColumn(Data.MIMETYPE, type); } private static Matcher<Cursor> hasValueForColumn(final String column, final String value) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; final Cursor cursor = (Cursor)o; final int index = cursor.getColumnIndexOrThrow(column); return value.equals(cursor.getString(index)); } @Override public void describeTo(Description description) { description.appendText("Cursor with " + column + "=" + value); } }; } private static Matcher<Cursor> hasRowMatching(final Matcher<Cursor> rowMatcher) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; final Cursor cursor = (Cursor)o; cursor.moveToPosition(-1); while (cursor.moveToNext()) { if (rowMatcher.matches(cursor)) return true; } return false; } @Override public void describeTo(Description description) { description.appendText("Cursor with row matching "); rowMatcher.describeTo(description); } }; } private static Matcher<Cursor> hasName(final String name) { return hasRowMatching(allOf( hasMimeType(StructuredName.CONTENT_ITEM_TYPE), hasValueForColumn( StructuredName.DISPLAY_NAME, name))); } private static Matcher<Cursor> hasPhone(final String phone) { return hasRowMatching(allOf( hasMimeType(Phone.CONTENT_ITEM_TYPE), hasValueForColumn( Phone.NUMBER, phone))); } private static Matcher<Cursor> hasEmail(final String email) { return hasRowMatching(allOf( hasMimeType(Email.CONTENT_ITEM_TYPE), hasValueForColumn( Email.ADDRESS, email))); } static class StringableCursor extends CursorWrapper { public StringableCursor(Cursor cursor) { super(cursor); } @Override public String toString() { final Cursor wrapped = getWrappedCursor(); if (wrapped.getCount() == 0) { return "Empty Cursor"; } return DatabaseUtils.dumpCursorToString(wrapped); } } private static String randomPhone() { return String.format(Locale.US, "1%s55501%02d", AREA_CODES[sRandom.nextInt(AREA_CODES.length)], Loading tests/src/com/android/contacts/tests/ContactsMatchers.java 0 → 100644 +147 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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 com.android.contacts.tests; import android.database.Cursor; import android.provider.ContactsContract; import com.android.contacts.model.SimContact; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; import static org.hamcrest.Matchers.allOf; /** * Has useful {@link org.hamcrest.Matchers}s for the Contacts app */ public class ContactsMatchers { private ContactsMatchers() { } /** * Matchers for {@link Cursor}s returned by queries to * {@link android.provider.ContactsContract.Data#CONTENT_URI} */ public static class DataCursor { public static Matcher<Cursor> hasMimeType(String type) { return hasValueForColumn(ContactsContract.Data.MIMETYPE, type); } public static Matcher<Cursor> hasName(final String name) { return hasRowMatching(allOf( hasMimeType(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE), hasValueForColumn( ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name))); } public static Matcher<Cursor> hasPhone(final String phone) { return hasRowMatching(allOf( hasMimeType(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE), hasValueForColumn( ContactsContract.CommonDataKinds.Phone.NUMBER, phone))); } public static Matcher<Cursor> hasEmail(final String email) { return hasRowMatching(allOf( hasMimeType(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE), hasValueForColumn( ContactsContract.CommonDataKinds.Email.ADDRESS, email))); } } public static Matcher<Cursor> hasCount(final int count) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; return ((Cursor)o).getCount() == count; } @Override public void describeTo(Description description) { description.appendText("Cursor with " + count + " rows"); } }; } public static Matcher<Cursor> hasValueForColumn(final String column, final String value) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; final Cursor cursor = (Cursor)o; final int index = cursor.getColumnIndexOrThrow(column); return value.equals(cursor.getString(index)); } @Override public void describeTo(Description description) { description.appendText("Cursor with " + column + "=" + value); } }; } public static Matcher<Cursor> hasRowMatching(final Matcher<Cursor> rowMatcher) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; final Cursor cursor = (Cursor)o; cursor.moveToPosition(-1); while (cursor.moveToNext()) { if (rowMatcher.matches(cursor)) return true; } return false; } @Override public void describeTo(Description description) { description.appendText("Cursor with row matching "); rowMatcher.describeTo(description); } }; } public static Matcher<SimContact> isSimContactWithNameAndPhone(final String name, final String phone) { return new BaseMatcher<SimContact>() { @Override public boolean matches(Object o) { if (!(o instanceof SimContact)) return false; SimContact other = (SimContact) o; return name.equals(other.getName()) && phone.equals(other.getPhone()); } @Override public void describeTo(Description description) { description.appendText("SimContact with name=" + name + " and phone=" + phone); } }; } } tests/src/com/android/contacts/tests/StringableCursor.java 0 → 100644 +42 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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 com.android.contacts.tests; import android.database.Cursor; import android.database.CursorWrapper; import android.database.DatabaseUtils; /** * Wrapper around a cursor with a custom toString that dumps the entire cursor data * * This is for providing more useful info during debugging and testing. */ public class StringableCursor extends CursorWrapper { public StringableCursor(Cursor cursor) { super(cursor); } @Override public String toString() { final Cursor wrapped = getWrappedCursor(); if (wrapped.getCount() == 0) { return "Empty Cursor"; } return DatabaseUtils.dumpCursorToString(wrapped); } } Loading
tests/src/com/android/contacts/database/SimContactDaoTests.java +15 −134 Original line number Diff line number Diff line Loading @@ -20,8 +20,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.OperationApplicationException; import android.database.Cursor; import android.database.CursorWrapper; import android.database.DatabaseUtils; import android.os.RemoteException; import android.provider.ContactsContract; import android.provider.ContactsContract.CommonDataKinds.Email; Loading @@ -43,13 +41,12 @@ import com.android.contacts.model.SimContact; import com.android.contacts.model.account.AccountWithDataSet; import com.android.contacts.common.test.mocks.MockContentProvider; import com.android.contacts.tests.AccountsTestHelper; import com.android.contacts.tests.ContactsMatchers; import com.android.contacts.tests.SimContactsTestHelper; import com.android.contacts.tests.StringableCursor; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.Matchers; import org.junit.After; import org.junit.AfterClass; Loading @@ -68,6 +65,10 @@ import java.util.Random; import java.util.Set; import static android.os.Build.VERSION_CODES; import static com.android.contacts.tests.ContactsMatchers.DataCursor.hasEmail; import static com.android.contacts.tests.ContactsMatchers.DataCursor.hasName; import static com.android.contacts.tests.ContactsMatchers.DataCursor.hasPhone; import static com.android.contacts.tests.ContactsMatchers.isSimContactWithNameAndPhone; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; Loading Loading @@ -127,19 +128,19 @@ public class SimContactDaoTests { ), mAccount); Cursor cursor = queryContactWithName("Test One"); assertThat(cursor, hasCount(2)); assertThat(cursor, ContactsMatchers.hasCount(2)); assertThat(cursor, hasName("Test One")); assertThat(cursor, hasPhone("15095550101")); cursor.close(); cursor = queryContactWithName("Test Two"); assertThat(cursor, hasCount(2)); assertThat(cursor, ContactsMatchers.hasCount(2)); assertThat(cursor, hasName("Test Two")); assertThat(cursor, hasPhone("15095550102")); cursor.close(); cursor = queryContactWithName("Test Three"); assertThat(cursor, hasCount(4)); assertThat(cursor, ContactsMatchers.hasCount(4)); assertThat(cursor, hasName("Test Three")); assertThat(cursor, hasPhone("15095550103")); assertThat(cursor, allOf(hasEmail("user@example.com"), hasEmail("user2@example.com"))); Loading @@ -156,7 +157,7 @@ public class SimContactDaoTests { Cursor cursor = queryAllDataInAccount(); assertThat(cursor, hasCount(1)); assertThat(cursor, ContactsMatchers.hasCount(1)); assertThat(cursor, hasName("Test importJustName")); cursor.close(); } Loading @@ -171,7 +172,7 @@ public class SimContactDaoTests { Cursor cursor = queryAllDataInAccount(); assertThat(cursor, hasCount(1)); assertThat(cursor, ContactsMatchers.hasCount(1)); assertThat(cursor, hasPhone("15095550111")); cursor.close(); } Loading @@ -190,11 +191,11 @@ public class SimContactDaoTests { ), mAccount); final Cursor contactsCursor = queryAllRawContactsInAccount(); assertThat(contactsCursor, hasCount(1)); assertThat(contactsCursor, ContactsMatchers.hasCount(1)); contactsCursor.close(); final Cursor dataCursor = queryAllDataInAccount(); assertThat(dataCursor, hasCount(1)); assertThat(dataCursor, ContactsMatchers.hasCount(1)); dataCursor.close(); } Loading @@ -218,12 +219,12 @@ public class SimContactDaoTests { sut.importContacts(contacts, mAccount); final Cursor contactsCursor = queryAllRawContactsInAccount(); assertThat(contactsCursor, hasCount(MAX_SIM_CONTACTS)); assertThat(contactsCursor, ContactsMatchers.hasCount(MAX_SIM_CONTACTS)); contactsCursor.close(); final Cursor dataCursor = queryAllDataInAccount(); // Each contact has one data row for each of name, phone and email assertThat(dataCursor, hasCount(MAX_SIM_CONTACTS * 3)); assertThat(dataCursor, ContactsMatchers.hasCount(MAX_SIM_CONTACTS * 3)); dataCursor.close(); } Loading Loading @@ -740,126 +741,6 @@ public class SimContactDaoTests { } } private static Matcher<SimContact> isSimContactWithNameAndPhone(final String name, final String phone) { return new BaseMatcher<SimContact>() { @Override public boolean matches(Object o) { if (!(o instanceof SimContact)) return false; SimContact other = (SimContact) o; return name.equals(other.getName()) && phone.equals(other.getPhone()); } @Override public void describeTo(Description description) { description.appendText("SimContact with name=" + name + " and phone=" + phone); } }; } private static Matcher<Cursor> hasCount(final int count) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; return ((Cursor)o).getCount() == count; } @Override public void describeTo(Description description) { description.appendText("Cursor with " + count + " rows"); } }; } private static Matcher<Cursor> hasMimeType(String type) { return hasValueForColumn(Data.MIMETYPE, type); } private static Matcher<Cursor> hasValueForColumn(final String column, final String value) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; final Cursor cursor = (Cursor)o; final int index = cursor.getColumnIndexOrThrow(column); return value.equals(cursor.getString(index)); } @Override public void describeTo(Description description) { description.appendText("Cursor with " + column + "=" + value); } }; } private static Matcher<Cursor> hasRowMatching(final Matcher<Cursor> rowMatcher) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; final Cursor cursor = (Cursor)o; cursor.moveToPosition(-1); while (cursor.moveToNext()) { if (rowMatcher.matches(cursor)) return true; } return false; } @Override public void describeTo(Description description) { description.appendText("Cursor with row matching "); rowMatcher.describeTo(description); } }; } private static Matcher<Cursor> hasName(final String name) { return hasRowMatching(allOf( hasMimeType(StructuredName.CONTENT_ITEM_TYPE), hasValueForColumn( StructuredName.DISPLAY_NAME, name))); } private static Matcher<Cursor> hasPhone(final String phone) { return hasRowMatching(allOf( hasMimeType(Phone.CONTENT_ITEM_TYPE), hasValueForColumn( Phone.NUMBER, phone))); } private static Matcher<Cursor> hasEmail(final String email) { return hasRowMatching(allOf( hasMimeType(Email.CONTENT_ITEM_TYPE), hasValueForColumn( Email.ADDRESS, email))); } static class StringableCursor extends CursorWrapper { public StringableCursor(Cursor cursor) { super(cursor); } @Override public String toString() { final Cursor wrapped = getWrappedCursor(); if (wrapped.getCount() == 0) { return "Empty Cursor"; } return DatabaseUtils.dumpCursorToString(wrapped); } } private static String randomPhone() { return String.format(Locale.US, "1%s55501%02d", AREA_CODES[sRandom.nextInt(AREA_CODES.length)], Loading
tests/src/com/android/contacts/tests/ContactsMatchers.java 0 → 100644 +147 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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 com.android.contacts.tests; import android.database.Cursor; import android.provider.ContactsContract; import com.android.contacts.model.SimContact; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; import static org.hamcrest.Matchers.allOf; /** * Has useful {@link org.hamcrest.Matchers}s for the Contacts app */ public class ContactsMatchers { private ContactsMatchers() { } /** * Matchers for {@link Cursor}s returned by queries to * {@link android.provider.ContactsContract.Data#CONTENT_URI} */ public static class DataCursor { public static Matcher<Cursor> hasMimeType(String type) { return hasValueForColumn(ContactsContract.Data.MIMETYPE, type); } public static Matcher<Cursor> hasName(final String name) { return hasRowMatching(allOf( hasMimeType(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE), hasValueForColumn( ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name))); } public static Matcher<Cursor> hasPhone(final String phone) { return hasRowMatching(allOf( hasMimeType(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE), hasValueForColumn( ContactsContract.CommonDataKinds.Phone.NUMBER, phone))); } public static Matcher<Cursor> hasEmail(final String email) { return hasRowMatching(allOf( hasMimeType(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE), hasValueForColumn( ContactsContract.CommonDataKinds.Email.ADDRESS, email))); } } public static Matcher<Cursor> hasCount(final int count) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; return ((Cursor)o).getCount() == count; } @Override public void describeTo(Description description) { description.appendText("Cursor with " + count + " rows"); } }; } public static Matcher<Cursor> hasValueForColumn(final String column, final String value) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; final Cursor cursor = (Cursor)o; final int index = cursor.getColumnIndexOrThrow(column); return value.equals(cursor.getString(index)); } @Override public void describeTo(Description description) { description.appendText("Cursor with " + column + "=" + value); } }; } public static Matcher<Cursor> hasRowMatching(final Matcher<Cursor> rowMatcher) { return new BaseMatcher<Cursor>() { @Override public boolean matches(Object o) { if (!(o instanceof Cursor)) return false; final Cursor cursor = (Cursor)o; cursor.moveToPosition(-1); while (cursor.moveToNext()) { if (rowMatcher.matches(cursor)) return true; } return false; } @Override public void describeTo(Description description) { description.appendText("Cursor with row matching "); rowMatcher.describeTo(description); } }; } public static Matcher<SimContact> isSimContactWithNameAndPhone(final String name, final String phone) { return new BaseMatcher<SimContact>() { @Override public boolean matches(Object o) { if (!(o instanceof SimContact)) return false; SimContact other = (SimContact) o; return name.equals(other.getName()) && phone.equals(other.getPhone()); } @Override public void describeTo(Description description) { description.appendText("SimContact with name=" + name + " and phone=" + phone); } }; } }
tests/src/com/android/contacts/tests/StringableCursor.java 0 → 100644 +42 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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 com.android.contacts.tests; import android.database.Cursor; import android.database.CursorWrapper; import android.database.DatabaseUtils; /** * Wrapper around a cursor with a custom toString that dumps the entire cursor data * * This is for providing more useful info during debugging and testing. */ public class StringableCursor extends CursorWrapper { public StringableCursor(Cursor cursor) { super(cursor); } @Override public String toString() { final Cursor wrapped = getWrappedCursor(); if (wrapped.getCount() == 0) { return "Empty Cursor"; } return DatabaseUtils.dumpCursorToString(wrapped); } }