1 /* 2 * Copyright (C) 2020 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 com.android.internal.telephony.testing; 18 19 import static com.google.common.truth.Truth.assertAbout; 20 21 import android.content.ContentValues; 22 import android.database.Cursor; 23 import android.database.CursorWrapper; 24 import android.database.DatabaseUtils; 25 26 import androidx.annotation.Nullable; 27 28 import com.google.common.truth.FailureMetadata; 29 import com.google.common.truth.IntegerSubject; 30 import com.google.common.truth.IterableSubject; 31 import com.google.common.truth.StringSubject; 32 import com.google.common.truth.Subject; 33 import com.google.common.truth.Truth; 34 35 import java.util.ArrayList; 36 import java.util.List; 37 38 /** Truth subject for making assertions about {@link Cursor}s. */ 39 public final class CursorSubject extends Subject { 40 41 private final Cursor mActual; 42 CursorSubject(FailureMetadata metadata, @Nullable Cursor actual)43 private CursorSubject(FailureMetadata metadata, @Nullable Cursor actual) { 44 super(metadata, new StringableCursor(actual)); 45 this.mActual = new StringableCursor(actual); 46 } 47 48 /** Returns the factory for this subject. */ cursors()49 public static Factory<CursorSubject, Cursor> cursors() { 50 return CursorSubject::new; 51 } 52 53 /** Starts an assertion. */ assertThat(Cursor cursor)54 public static CursorSubject assertThat(Cursor cursor) { 55 return assertAbout(cursors()).that(cursor); 56 } 57 58 /** Asserts {@link Cursor#getCount()} has the specified value. */ hasCount(int count)59 public void hasCount(int count) { 60 check("getCount()").that(mActual.getCount()).isEqualTo(count); 61 } 62 63 /** Asserts {@link Cursor#getColumnNames()} match those specified. */ hasColumnNames(String... columnNames)64 public void hasColumnNames(String... columnNames) { 65 check("getColumnNames()").that(mActual.getColumnNames()).asList() 66 .containsExactlyElementsIn(columnNames).inOrder(); 67 } 68 69 /** Positions the cursor under test at the specified row to make an assertion about it. */ atRow(int position)70 public CursorSubject atRow(int position) { 71 check("moveToPosition").that(mActual.moveToPosition(position)).isTrue(); 72 return this; 73 } 74 75 /** Asserts that the row at the cursor's current position has the specified values. */ hasRowValues(Object... values)76 public CursorSubject hasRowValues(Object... values) { 77 check("getColumnCount()").that(mActual.getColumnCount()).isEqualTo(values.length); 78 ContentValues expectedValues = new ContentValues(); 79 for (int i = 0; i < values.length; i++) { 80 expectedValues.put(mActual.getColumnName(i), values[i].toString()); 81 } 82 83 ContentValues actualValues = new ContentValues(); 84 DatabaseUtils.cursorRowToContentValues(mActual, actualValues); 85 86 check("Row: %s", mActual.getPosition()).that(actualValues).isEqualTo(expectedValues); 87 return this; 88 } 89 90 /** Asserts that the cursor has a single row with the specified values. */ hasSingleRow(Object... values)91 public void hasSingleRow(Object... values) { 92 hasCount(1); 93 atRow(0).hasRowValues(values); 94 } 95 96 /** 97 * Asserts that the row at the cursor's current position has the specified value for the 98 * specified column. 99 */ hasRowValue(String columnName, Object value)100 public CursorSubject hasRowValue(String columnName, Object value) { 101 int index = mActual.getColumnIndex(columnName); 102 check("getColumnIndex()").that(index).isNotEqualTo(-1); 103 104 check("Row[%s]: %s", columnName, index).that(mActual.getString(index)) 105 .isEqualTo(value.toString()); 106 return this; 107 } 108 109 /** Starts an assertion about the value of the specified column for the current row. */ intField(String columnName)110 public IntegerSubject intField(String columnName) { 111 int index = mActual.getColumnIndex(columnName); 112 check("getColumnIndex()").that(index).isNotEqualTo(-1); 113 check("getType()").that(mActual.getType(index)).isEqualTo(Cursor.FIELD_TYPE_INTEGER); 114 115 return check("getInt()").that(mActual.getInt(index)); 116 } 117 118 /** Starts an assertion about the value of the specified column for the current row. */ stringField(String columnName)119 public StringSubject stringField(String columnName) { 120 int index = mActual.getColumnIndex(columnName); 121 check("getColumnIndex()").that(index).isNotEqualTo(-1); 122 check("getType()").that(mActual.getType(index)).isEqualTo(Cursor.FIELD_TYPE_STRING); 123 124 return check("getString()").that(mActual.getString(index)); 125 } 126 127 /** Asserts that the cursor rows match the data specified. */ hasData(Object[][] rows)128 public void hasData(Object[][] rows) { 129 hasCount(rows.length); 130 for (int i = 0; i < rows.length; i++) { 131 atRow(i).hasRowValues(rows[i]); 132 } 133 } 134 135 /** Starts an assertion about the cursor's rows. */ asLists()136 public IterableSubject asLists() { 137 List<List<String>> result = new ArrayList<>(); 138 mActual.moveToPosition(-1); 139 while (mActual.moveToNext()) { 140 List<String> row = new ArrayList<>(); 141 for (int i = 0; i < mActual.getColumnCount(); i++) { 142 row.add(mActual.getString(i)); 143 } 144 result.add(row); 145 } 146 return Truth.assertThat(result); 147 } 148 149 private static class StringableCursor extends CursorWrapper { 150 StringableCursor(Cursor cursor)151 StringableCursor(Cursor cursor) { 152 super(cursor); 153 } 154 155 @Override toString()156 public String toString() { 157 return DatabaseUtils.dumpCursorToString(getWrappedCursor()); 158 } 159 } 160 161 } 162