Output:
Chunk ID: 39ae8b
Wall time: 0.4011 seconds
Process exited with code 0
Original token count: 11206
Output:
Total output lines: 535

app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:17:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:81:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:83:    @Test
app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:90:    @Test
app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:97:    @Test
app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:104:    @Test
app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:119:    @Test
app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:126:    @Test
app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:148:    @Test
app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:156:    @Test
app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:164:    @Test
app/src/test/java/com/yorvana/YorvanaApplicationTest.kt:182:    @Test
app/src/test/java/com/yorvana/util/FileProviderHelperTest.kt:35:    @Test
app/src/test/java/com/yorvana/util/FileProviderHelperTest.kt:67:    @Test
app/src/test/java/com/yorvana/util/FileProviderHelperTest.kt:86:    @Test
app/src/test/java/com/yorvana/util/FileProviderHelperTest.kt:96:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:38:import org.junit.runner.RunWith
app/src/androidTest/java/com/yorvana/SmokeTest.kt:42: * Smoke tests for Yorvana.
app/src/androidTest/java/com/yorvana/SmokeTest.kt:47:@RunWith(AndroidJUnit4::class)
app/src/androidTest/java/com/yorvana/SmokeTest.kt:48:class SmokeTest {
app/src/androidTest/java/com/yorvana/SmokeTest.kt:66:        Log.d("SmokeTest", "STEP: $name - $description")
app/src/androidTest/java/com/yorvana/SmokeTest.kt:119:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:126:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:140:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:168:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:186:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:195:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:213:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:229:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:248:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:270:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:305:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:338:    @Test
app/src/androidTest/java/com/yorvana/SmokeTest.kt:377:    @Test
app/src/test/java/com/yorvana/util/SentryWrapperTest.kt:17:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/util/SentryWrapperTest.kt:21:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/util/SentryWrapperTest.kt:40:    @Test
app/src/test/java/com/yorvana/util/SentryWrapperTest.kt:65:    @Test
app/src/test/java/com/yorvana/util/VaultPathHelperTest.kt:27:    @Test
app/src/test/java/com/yorvana/util/VaultPathHelperTest.kt:38:    @Test
app/src/test/java/com/yorvana/util/VaultPathHelperTest.kt:49:    @Test
app/src/test/java/com/yorvana/util/VaultPathHelperTest.kt:60:    @Test
app/src/test/java/com/yorvana/util/VaultPathHelperTest.kt:69:    @Test
app/src/test/java/com/yorvana/util/VaultPathHelperTest.kt:76:    @Test
app/src/test/java/com/yorvana/util/VaultPathHelperTest.kt:83:    @Test
app/src/test/java/com/yorvana/util/VaultPathHelperTest.kt:89:    @Test
app/src/test/java/com/yorvana/util/DateFormatterTest.kt:9:    @Test
app/src/test/java/com/yorvana/util/DateFormatterTest.kt:19:    @Test
app/src/test/java/com/yorvana/util/DateFormatterTest.kt:26:    @Test
app/src/test/java/com/yorvana/util/DateFormatterTest.kt:38:    @Test
app/src/test/java/com/yorvana/util/DateFormatterTest.kt:51:    @Test
app/src/test/java/com/yorvana/util/DateFormatterTest.kt:58:    @Test
app/src/test/java/com/yorvana/util/DateFormatterTest.kt:65:    @Test
app/src/test/java/com/yorvana/MainActivityTest.kt:19:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/MainActivityTest.kt:23:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/MainActivityTest.kt:43:    @Test
app/src/test/java/com/yorvana/MainActivityTest.kt:57:    @Test
app/src/test/java/com/yorvana/MainActivityTest.kt:74:    @Test
app/src/test/java/com/yorvana/MainActivityTest.kt:91:    @Test
app/src/test/java/com/yorvana/MainActivityTest.kt:103:    @Test
app/src/test/java/com/yorvana/MainActivityTest.kt:116:    @Test
app/src/test/java/com/yorvana/MainActivityTest.kt:129:    @Test
app/src/test/java/com/yorvana/MainActivityTest.kt:139:    @Test
app/src/test/java/com/yorvana/util/CrashReporterTest.kt:11:    @Test
app/src/test/java/com/yorvana/util/CrashReporterTest.kt:51:    @Test
app/src/test/java/com/yorvana/util/CrashReporterTest.kt:67:    @Test
app/src/test/java/com/yorvana/util/CrashReporterTest.kt:85:    @Test
app/src/test/java/com/yorvana/util/UuidGeneratorTest.kt:7:    @Test
app/src/test/java/com/yorvana/util/UuidGeneratorTest.kt:14:    @Test
app/src/test/java/com/yorvana/domain/AppGateTest.kt:41:    @Test
app/src/test/java/com/yorvana/domain/AppGateTest.kt:49:    @Test
app/src/test/java/com/yorvana/domain/AppGateTest.kt:57:    @Test
app/src/test/java/com/yorvana/domain/AppGateTest.kt:65:    @Test
app/src/test/java/com/yorvana/domain/AppGateTest.kt:73:    @Test
app/src/test/java/com/yorvana/domain/AppGateTest.kt:81:    @Test
app/src/androidTest/java/com/yorvana/screenshots/StoreScreenshotTest.kt:18:import org.junit.runner.RunWith
app/src/androidTest/java/com/yorvana/screenshots/StoreScreenshotTest.kt:20:@RunWith(AndroidJUnit4::class)
app/src/androidTest/java/com/yorvana/screenshots/StoreScreenshotTest.kt:23:    @Test
app/src/androidTest/java/com/yorvana/screenshots/StoreScreenshotTest.kt:30:    @Test
app/src/androidTest/java/com/yorvana/screenshots/StoreScreenshotTest.kt:38:    @Test
app/src/androidTest/java/com/yorvana/screenshots/StoreScreenshotTest.kt:47:    @Test
app/src/androidTest/java/com/yorvana/screenshots/StoreScreenshotTest.kt:60:    @Test
app/src/androidTest/java/com/yorvana/screenshots/StoreScreenshotTest.kt:72:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenTest.kt:18:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenTest.kt:22:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenTest.kt:28:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenTest.kt:49:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenshotTest.kt:49:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenshotTest.kt:55:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenshotTest.kt:61:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenshotTest.kt:67:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenTest.kt:21:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenTest.kt:26:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenTest.kt:45:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenTest.kt:58:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenTest.kt:65:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenTest.kt:72:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenTest.kt:99:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenTest.kt:121:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenIT.kt:18:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenIT.kt:23:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenIT.kt:28:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenIT.kt:48:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleScreenIT.kt:74:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelTest.kt:123:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelTest.kt:138:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelTest.kt:164:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelTest.kt:177:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelTest.kt:192:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelTest.kt:207:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelTest.kt:223:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelTest.kt:235:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelTest.kt:247:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelTest.kt:257:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelTest.kt:266:    @Test
app/src/test/java/com/yorvana/ui/navigation/SetupScreenTest.kt:9:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/navigation/SetupScreenTest.kt:13:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/navigation/SetupScreenTest.kt:19:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:14:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:20:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:51:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:58:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:72:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:87:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:97:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:108:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:120:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:147:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:155:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:165:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:173:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:184:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:191:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:201:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:220:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:230:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:237:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:247:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:272:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:285:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:298:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:308:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:324:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:341:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:351:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:362:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplIT.kt:401:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:95:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:118:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:131:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:145:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:163:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:175:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:188:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:205:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:220:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:230:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:252:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:267:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:285:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:300:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:310:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:319:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:331:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:343:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:355:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:370:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:384:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListViewModelTest.kt:397:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelIT.kt:36:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelIT.kt:43:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelIT.kt:102:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailViewModelIT.kt:130:    @Test
app/src/test/java/com/yorvana/ui/util/EmailLaunchRequestTest.kt:20:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/util/EmailLaunchRequestTest.kt:25:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/util/EmailLaunchRequestTest.kt:28:    @Test
app/src/test/java/com/yorvana/ui/util/EmailLaunchRequestTest.kt:55:    @Test
app/src/test/java/com/yorvana/ui/navigation/SetupScreenshotTest.kt:17:    @Test
app/src/test/java/com/yorvana/ui/navigation/SetupScreenshotTest.kt:27:    @Test
app/src/test/java/com/yorvana/ui/navigation/SetupScreenshotTest.kt:37:    @Test
app/src/test/java/com/yorvana/ui/navigation/SetupScreenshotTest.kt:47:    @Test
app/src/test/java/com/yorvana/ui/navigation/SetupScreenshotTest.kt:59:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:28:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:33:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:76:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:91:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:111:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:127:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:140:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:161:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:188:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:214:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:243:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:267:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugViewModelTest.kt:289:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailScreenTest.kt:22:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/records/VehicleDetailScreenTest.kt:27:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/records/VehicleDetailScreenTest.kt:32:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailScreenTest.kt:64:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailScreenTest.kt:130:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailScreenTest.kt:158:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplTest.kt:17:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/data/storage/VaultStorageImplTest.kt:23:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/data/storage/VaultStorageImplTest.kt:56:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplTest.kt:63:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplTest.kt:79:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplTest.kt:97:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplTest.kt:108:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplTest.kt:123:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplTest.kt:148:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplTest.kt:164:    @Test
app/src/test/java/com/yorvana/data/storage/VaultStorageImplTest.kt:174:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListScreenshotTest.kt:83:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListScreenshotTest.kt:89:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListScreenshotTest.kt:95:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListScreenshotTest.kt:101:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListScreenshotTest.kt:107:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListScreenshotTest.kt:113:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenshotTest.kt:40:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenshotTest.kt:46:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenshotTest.kt:61:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenshotTest.kt:80:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenshotTest.kt:91:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenshotTest.kt:106:    @Test
app/src/test/java/com/yorvana/ui/reportbug/ReportBugScreenshotTest.kt:121:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:44:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:49:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:101:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:113:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:120:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:128:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:135:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:142:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:150:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:158:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:165:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:173:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:180:    @Test
app/src/test/java/com/yorvana/ui/util/ViewModelFactoryTest.kt:187:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordViewModelTest.kt:91:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordViewModelTest.kt:100:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordViewModelTest.kt:123:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordViewModelTest.kt:143:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordViewModelTest.kt:168:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordViewModelTest.kt:179:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordViewModelTest.kt:190:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordViewModelTest.kt:202:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordViewModelTest.kt:214:    @Test
app/src/…1206 tokens truncated…ExtensionsTest.kt:31:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailScreenIT.kt:15:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/records/RecordDetailScreenIT.kt:20:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/records/RecordDetailScreenIT.kt:25:    @Test
app/src/test/java/com/yorvana/ui/records/RecordDetailScreenIT.kt:65:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordScreenIT.kt:19:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/records/AddEditRecordScreenIT.kt:24:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/records/AddEditRecordScreenIT.kt:29:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordScreenIT.kt:51:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordScreenIT.kt:94:    @Test
app/src/test/java/com/yorvana/data/preferences/AppPreferencesImplTest.kt:43:    @Test
app/src/test/java/com/yorvana/data/preferences/AppPreferencesImplTest.kt:58:    @Test
app/src/test/java/com/yorvana/data/preferences/AppPreferencesImplTest.kt:82:    @Test
app/src/test/java/com/yorvana/data/preferences/AppPreferencesImplTest.kt:90:    @Test
app/src/test/java/com/yorvana/data/preferences/AppPreferencesImplTest.kt:98:    @Test
app/src/test/java/com/yorvana/data/preferences/AppPreferencesImplTest.kt:106:    @Test
app/src/test/java/com/yorvana/data/preferences/AppPreferencesImplTest.kt:114:    @Test
app/src/test/java/com/yorvana/data/preferences/AppPreferencesImplTest.kt:122:    @Test
app/src/test/java/com/yorvana/data/preferences/AppPreferencesImplTest.kt:131:    @Test
app/src/test/java/com/yorvana/data/preferences/AppPreferencesImplTest.kt:139:    @Test
app/src/test/java/com/yorvana/data/preferences/AppPreferencesImplTest.kt:148:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListConsentDialogTest.kt:26:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/vehicles/VehicleListConsentDialogTest.kt:31:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/vehicles/VehicleListConsentDialogTest.kt:52:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListConsentDialogTest.kt:61:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListConsentDialogTest.kt:75:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListConsentDialogTest.kt:87:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListConsentDialogTest.kt:99:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListConsentDialogTest.kt:107:    @Test
app/src/test/java/com/yorvana/ui/vehicles/VehicleListConsentDialogTest.kt:116:    @Test
app/src/test/java/com/yorvana/ui/util/BaseScreenshotTest.kt:7:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/util/BaseScreenshotTest.kt:11:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/components/RequiredLabelTest.kt:19:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/components/RequiredLabelTest.kt:23:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/components/RequiredLabelTest.kt:29:    @Test
app/src/test/java/com/yorvana/ui/components/RequiredLabelTest.kt:65:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:56:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:82:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:113:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:125:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:136:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:166:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:184:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:195:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:205:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:217:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:233:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:242:    @Test
app/src/test/java/com/yorvana/data/repository/RecordRepositoryImplTest.kt:254:    @Test
app/src/test/java/com/yorvana/ui/records/ImageViewerScreenshotTest.kt:17:    @Test
app/src/test/java/com/yorvana/data/repository/WorkflowIntegrationIT.kt:17:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/data/repository/WorkflowIntegrationIT.kt:24:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/data/repository/WorkflowIntegrationIT.kt:54:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:84:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:96:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:105:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:114:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:123:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:141:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:160:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:168:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:176:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:184:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:192:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:200:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:208:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:217:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:226:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:235:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:244:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:253:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:270:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:291:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelTest.kt:307:    @Test
app/src/test/java/com/yorvana/data/repository/DataIntegrationIT.kt:17:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/data/repository/DataIntegrationIT.kt:25:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/data/repository/DataIntegrationIT.kt:54:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordScreenshotTest.kt:47:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordScreenshotTest.kt:53:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordScreenshotTest.kt:59:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordScreenshotTest.kt:65:    @Test
app/src/test/java/com/yorvana/ui/records/AddEditRecordScreenshotTest.kt:71:    @Test
app/src/test/java/com/yorvana/data/repository/CategoryRepositoryImplTest.kt:57:    @Test
app/src/test/java/com/yorvana/data/repository/CategoryRepositoryImplTest.kt:84:    @Test
app/src/test/java/com/yorvana/data/repository/CategoryRepositoryImplTest.kt:119:    @Test
app/src/test/java/com/yorvana/data/repository/CategoryRepositoryImplTest.kt:151:    @Test
app/src/test/java/com/yorvana/data/repository/CategoryRepositoryImplTest.kt:158:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:62:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:68:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:74:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:80:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:86:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:92:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:98:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:104:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:110:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:118:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:128:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenshotTest.kt:139:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailScreenshotTest.kt:69:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailScreenshotTest.kt:75:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailScreenshotTest.kt:81:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailScreenshotTest.kt:92:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:89:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:116:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:128:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:140:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:162:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:179:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:192:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:206:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:220:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:235:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:247:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:259:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:267:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:277:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:286:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:298:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:308:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:320:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:338:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:347:    @Test
app/src/test/java/com/yorvana/ui/records/VehicleDetailViewModelTest.kt:356:    @Test
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelIT.kt:32:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelIT.kt:39:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/vehicles/AddEditVehicleViewModelIT.kt:68:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:51:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:67:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:86:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:98:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:109:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:121:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:131:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:151:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:168:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:177:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:192:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:208:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:227:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:236:    @Test
app/src/test/java/com/yorvana/data/repository/VehicleRepositoryImplTest.kt:248:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelIT.kt:40:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelIT.kt:47:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelIT.kt:84:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelIT.kt:133:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelIT.kt:173:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelIT.kt:239:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelIT.kt:275:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesScreenshotTest.kt:42:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesScreenshotTest.kt:48:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesScreenshotTest.kt:54:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesScreenTest.kt:16:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/settings/CategoriesScreenTest.kt:20:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/settings/CategoriesScreenTest.kt:26:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesScreenIT.kt:19:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/settings/CategoriesScreenIT.kt:24:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/settings/CategoriesScreenIT.kt:29:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesScreenIT.kt:55:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:71:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:92:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:101:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:114:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:124:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:138:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:151:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:164:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:179:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:193:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:204:    @Test
app/src/test/java/com/yorvana/ui/settings/CategoriesViewModelTest.kt:214:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenIT.kt:20:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/settings/SettingsScreenIT.kt:25:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/settings/SettingsScreenIT.kt:30:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenIT.kt:68:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenIT.kt:98:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenIT.kt:126:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenIT.kt:158:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsScreenIT.kt:177:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:114:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:129:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:139:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:151:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:169:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:182:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:196:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:211:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:230:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:242:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:258:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:274:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:290:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:306:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:318:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:344:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:360:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:376:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:407:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:417:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:427:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:437:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:452:    @Test
app/src/test/java/com/yorvana/ui/settings/SettingsViewModelTest.kt:468:    @Test
app/src/test/java/com/yorvana/ui/components/UpgradeDialogScreenshotTest.kt:13:    @Test
app/src/test/java/com/yorvana/ui/components/UpgradeDialogScreenshotTest.kt:23:    @Test
app/src/test/java/com/yorvana/ui/components/UpgradeDialogTest.kt:11:import org.junit.runner.RunWith
app/src/test/java/com/yorvana/ui/components/UpgradeDialogTest.kt:15:@RunWith(RobolectricTestRunner::class)
app/src/test/java/com/yorvana/ui/components/UpgradeDialogTest.kt:21:    @Test
app/src/test/java/com/yorvana/ui/components/PaywallStatusCardScreenshotTest.kt:22:    @Test
app/src/test/java/com/yorvana/ui/components/PaywallStatusCardScreenshotTest.kt:38:    @Test
app/src/test/java/com/yorvana/ui/components/PaywallStatusCardScreenshotTest.kt:54:    @Test
app/src/test/java/com/yorvana/ui/components/PaywallStatusCardScreenshotTest.kt:70:    @Test
app/src/test/java/com/yorvana/ui/components/PaywallInfoSheetScreenshotTest.kt:21:    @Test
app/src/test/java/com/yorvana/ui/components/PaywallInfoSheetScreenshotTest.kt:36:    @Test
app/src/test/java/com/yorvana/ui/components/PaywallInfoSheetScreenshotTest.kt:51:    @Test
app/src/test/java/com/yorvana/ui/components/PaywallInfoSheetScreenshotTest.kt:66:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:22:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:36:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:58:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:73:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:86:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:99:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:112:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:122:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:144:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:166:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:181:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:196:    @Test
app/src/test/java/com/yorvana/ui/components/ComponentScreenshotTest.kt:209:    @Test
app/src/test/java/com/yorvana/ui/components/PaywallScaffoldScreenshotTest.kt:28:    @Test
app/src/test/java/com/yorvana/ui/components/PaywallScaffoldScreenshotTest.kt:49:    @Test


Output:
Chunk ID: 30c077
Wall time: 0.1194 seconds
Process exited with code 0
Original token count: 2806
Output:
    dependsOn(smokeTask)

    from(layout.buildDirectory.dir("outputs/managed_device_code_coverage/debug/pixel2api33")) {
        include("coverage.ec")
    }
    into(layout.projectDirectory.dir("coverage-baselines"))
    rename { "gmd_smoke.ec" }

    includeEmptyDirs = false
    duplicatesStrategy = DuplicatesStrategy.FAIL

    doLast {
        val destFile = layout.projectDirectory.file("coverage-baselines/gmd_smoke.ec").asFile
        if (!destFile.exists()) {
            throw GradleException("Failed to generate GMD coverage. Expected file not found: $destFile")
        }
    }
}

val storeScreenshotFiles =
    listOf(
        "screen_01_vehicle_list.png",
        "screen_02_vehicle_detail.png",
        "screen_03_add_record.png",
        "screen_04_categories.png",
        "screen_05_settings_privacy.png",
        "screen_06_paywall_dialog.png",
    )
val storeScreenshotsRoot = rootProject.layout.projectDirectory.dir("distribution/store-assets/screenshots")
val storeAdditionalOutputRoot = layout.buildDirectory.dir("outputs/managed_device_android_test_additional_output/$testVariant")

fun registerStoreScreenshotCopy(
    taskPrefix: String,
    deviceTaskName: String,
    outputDirectory: String,
    previousCopyTask: TaskProvider<out Task>? = null,
): TaskProvider<Copy> {
    tasks.named<Task>(deviceTaskName).configure {
        previousCopyTask?.let { mustRunAfter(it) }
        // We inject a doFirst block to wipe the additional output root before every run.
        // This ensures a clean state for the subsequent copy task, but has the side-effect
        // of clearing previous outputs even when running a single device test for debugging.
        doFirst {
            delete(storeAdditionalOutputRoot)
        }
    }

    return tasks.register<Copy>("copy${taskPrefix}StoreScreenshots") {
        previousCopyTask?.let { dependsOn(it) }
        dependsOn(deviceTaskName)
        into(storeScreenshotsRoot.dir(outputDirectory))
        includeEmptyDirs = false
        duplicatesStrategy = DuplicatesStrategy.FAIL

        doFirst {
            delete(storeScreenshotsRoot.dir(outputDirectory))
        }

        from(storeAdditionalOutputRoot) {
            // AGP sometimes aliases instrumentation arguments across GMD tasks,
            // leading to screenshots being saved in the wrong bucket subfolder on the host.
            // We use a wildcard to grab any screenshot found in the device's output root.
            include("**/$outputDirectory/screen_*.png")
            eachFile {
                relativePath = RelativePath(true, name)
            }
        }

        doLast {
            val missing =
                storeScreenshotFiles.mapNotNull { fileName ->
                    val file = storeScreenshotsRoot.file("$outputDirectory/$fileName").asFile
                    if (file.exists()) null else file
                }
            if (missing.isNotEmpty()) {
                throw GradleException(
                    "Missing generated store screenshots for $outputDirectory:\n" +
                        missing.joinToString(separator = "\n") { "- ${it.path}" },
                )
            }
        }
    }
}

afterEvaluate {
    val copyPhoneStoreScreenshots =
        registerStoreScreenshotCopy(
            taskPrefix = "Phone",
            deviceTaskName = "phonePixel6api34${testVariantCap}AndroidTest",
            outputDirectory = "phone",
        )
    val copyTablet7StoreScreenshots =
        registerStoreScreenshotCopy(
            taskPrefix = "Tablet7",
            deviceTaskName = "tablet7Nexus7api34${testVariantCap}AndroidTest",
            outputDirectory = "tablet-7",
            previousCopyTask = copyPhoneStoreScreenshots,
        )
    val copyTablet10StoreScreenshots =
        registerStoreScreenshotCopy(
            taskPrefix = "Tablet10",
            deviceTaskName = "tablet10PixelTabletApi34${testVariantCap}AndroidTest",
            outputDirectory = "tablet-10",
            previousCopyTask = copyTablet7StoreScreenshots,
        )

    tasks.register("generateStoreScreenshots") {
        group = "Verification"
        description = "Runs store screenshot tests on managed devices and copies PNGs into distribution assets."

        dependsOn(copyTablet10StoreScreenshots)
    }
}

tasks.register<JacocoReport>("verifyWithCoverage") {
    group = "Verification"
    description = "Runs JVM unit tests and generates a combined coverage report using JaCoCo with the static GMD baseline."

    // Unit tests are variant-agnostic; we always use debug for coverage consistency
    dependsOn("testDebugUnitTest")

    reports {
        xml.required.set(true)
        html.required.set(true)
    }

    val classFilter =
        listOf(
            "**/R.class",
            "**/R$*.class",
            "**/BuildConfig.*",
            "**/Manifest*.*",
            "**/*Test*.*",
            "android/**/*.*",
            "**/*_ViewBinding*.*",
            "**/*_MembersInjector*.*",
            "**/*_Factory*.*",
            "**/*_Provide*Factory*.*",
            "**/*ExtensionsKt*.*",
            // ComposableSingletons are compiler-generated classes for @Composable lambdas
            // that are often static and difficult to cover in unit tests, creating noise.
            "**/*ComposableSingletons*.*",
        )

    val debugTree =
        fileTree(layout.buildDirectory.dir("tmp/kotlin-classes/debug")) {
            exclude(classFilter)
        }
    val javaTree =
        fileTree(layout.buildDirectory.dir("intermediates/javac/debug/classes")) {
            exclude(classFilter)
        }

    classDirectories.setFrom(files(debugTree, javaTree))
    sourceDirectories.setFrom(
        files(
            "src/main/java",
            "src/main/kotlin",
            "src/debug/java",
            "src/debug/kotlin",
        ),
    )

    // Collect all execution data from both unit tests and instrumented tests
    // Using specific roots to avoid implicit dependency issues with other tasks' outputs in the build folder
    val executionDataFiles =
        files(
            fileTree(layout.buildDirectory.dir("outputs/unit_test_code_coverage")) { include("**/*.exec") },
            layout.projectDirectory.file("coverage-baselines/gmd_smoke.ec"),
            fileTree(layout.buildDirectory.dir("jacoco")) { include("**/*.exec") },
        )

    executionData.setFrom(executionDataFiles)

    doFirst {
        val lfsBaseline = layout.projectDirectory.file("coverage-baselines/gmd_smoke.ec").asFile
        if (!lfsBaseline.exists()) {
            throw GradleException(
                "Required coverage baseline is missing: ${lfsBaseline.path}. " +
                    "Run 'git lfs pull' to fetch tracked baselines or './gradlew generateGmdCoverage' to regenerate it.",
            )
        }
        if (lfsBaseline.length() < 1000) {
            val header = lfsBaseline.inputStream().use { it.readNBytes(100) }.toString(Charsets.UTF_8)
            if (header.startsWith("version https://git-lfs.github.com/spec/v1")) {
                throw GradleException("Coverage baseline is a Git LFS pointer. Please run 'git lfs pull' to fetch the actual file.")
            }
        }

        val existingFiles = executionDataFiles.files.filter { it.exists() }
        val dynamicExecutionFiles = existingFiles.filter { it.name != "gmd_smoke.ec" }
        if (dynamicExecutionFiles.isEmpty()) {
            throw GradleException(
                "No dynamic JaCoCo execution data files were found. " +
                    "Ensure tests were executed with coverage enabled (e.g., via -Pcoverage).\n" +
                    "Searched in:\n" +
                    "- ${layout.buildDirectory.dir("outputs/unit_test_code_coverage").get()}\n" +
                    "- ${layout.buildDirectory.dir("jacoco").get()}",
            )
        }
    }
}

tasks.withType<Test>().configureEach {
    if (isCoverageEnabled) {
        configure<JacocoTaskExtension> {
            isEnabled = true
            // Required for Robolectric
            isIncludeNoLocationClasses = true
            excludes = listOf("jdk.internal.*")
        }
    } else {
        configure<JacocoTaskExtension> { isEnabled = false }
    }

    val defaultForks = (Runtime.getRuntime().availableProcessors() / 4).coerceAtLeast(2)
    maxParallelForks = (project.findProperty("testForks") as String?)?.toInt() ?: defaultForks
    forkEvery = 0L

    minHeapSize = "512m"
    maxHeapSize = "1536m"
    jvmArgs =
        listOf(
            "-XX:+UseG1GC",
            "-XX:MaxMetaspaceSize=512m",
            "-Dfile.encoding=UTF-8",
        )

    systemProperty("robolectric.graphicsMode", "NATIVE")
    // Exclude tests tagged @Category(LocalOnly::class) from automated Gradle runs.
    // These tests are intended to be run directly from the IDE.
    // Note: This project uses JUnit 4 exclusively. If a Jupiter runner is ever added,
    // useJUnit { } will need to be scoped to only JUnit 4 tasks to avoid overriding
    // Jupiter configuration.
    if (name.contains("Release")) {
        enabled = false
    }
    useJUnit {
        excludeCategories("com.yorvana.LocalOnly")
    }

    reports {
        html.required.set(System.getenv("CI") != null)
        junitXml.required.set(true)
    }
}

dependencies {
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.activity.compose)
    implementation(libs.androidx.documentfile)
    implementation(libs.sentry.android)
    implementation(platform(libs.compose.bom))
    implementation(libs.compose.ui)
    implementation(libs.compose.ui.tooling.preview)
    implementation(libs.compose.material3)
    implementation(libs.compose.material.icons.extended)
    implementation(libs.navigation3.runtime)
    implementation(libs.navigation3.ui)
    implementation(libs.lifecycle.viewmodel.compose)
    implementation(libs.lifecycle.viewmodel.savedstate)
    implementation(libs.lifecycle.runtime.compose)
    implementation(libs.datastore.preferences)
    implementation(libs.kotlinx.serialization.json)
    implementation(libs.kotlinx.coroutines.android)
    implementation(libs.coil.compose)
    implementation(libs.google.billing)

    debugImplementation(libs.compose.ui.tooling)
    debugImplementation(libs.compose.ui.test.manifest)

    testImplementation(libs.junit)
    testImplementation(libs.kotlinx.coroutines.test)
    testImplementation(libs.mockk)
    testImplementation(libs.truth)
    testImplementation(libs.turbine)
    testImplementation(libs.robolectric)
    testImplementation(libs.compose.ui.test)
    testImplementation(libs.androidx.test.ext)
    testImplementation(libs.roborazzi)
    testImplementation(libs.roborazzi.compose)

    androidTestImplementation(platform(libs.compose.bom))
    androidTestImplementation(libs.androidx.test.ext)
    androidTestImplementation(libs.compose.ui.test)
    androidTestImplementation(libs.mockk.android)
    androidTestImplementation(libs.truth)
    androidTestImplementation(libs.turbine)
    androidTestImplementation(libs.roborazzi)
    androidTestImplementation(libs.roborazzi.compose)
    androidTestImplementation(libs.uiautomator)
    androidTestImplementation(libs.espresso.intents)
}


A key detail surfaced: if `pixel2api33DebugAndroidTest` always receives the smoke `annotation=Smoke` from the build script, a child `regressionCheck` invocation that also passes `annotation=Regression` can collide. The plan should explicitly make the smoke injection conditional on “no explicit runner annotation property was supplied,” so the same exact device task can be reused safely by smoke and regression.


find app/src/androidTest/assets -type f -maxdepth 4 -print | sort


Output:
Chunk ID: b2566a
Wall time: 0.3147 seconds
Process exited with code 0
Original token count: 3474
Output:
26:| Google Play Billing sandbox | Test APK built from a non-debug build type signed with the same upload key as the Play internal track (the app module currently defaults instrumentation to `testBuildType = "debug"` per `app/build.gradle.kts:68`, which produces a debug-signed APK Play won't recognise as the internal-track artifact) + license tester accounts on a **Play-enabled device** (Play Store system image — `google_apis_playstore`, not the AOSP-only GMD pool; see [§5 Billing sandbox device path](#5-billing-sandbox-device-path)); gated by the **multi-precondition `Assume.assumeTrue` skip guard** from #118 (`BILLING_SANDBOX_ACCOUNT`, signing material, selected device path, signed-in Play account, and a `BillingClient.queryProductDetailsAsync(premium_lifetime)` non-empty result) so any missing prerequisite skips cleanly with a specific assumption message — *not* a narrow `BILLING_SANDBOX_ACCOUNT`-only gate | `regression/billing/` |
27:| Performance NFRs | **Macrobenchmark** (`androidx.benchmark`) in a separate module, running on its own dedicated GMD entry registered inside `:macrobenchmark` (a Pixel 2 API 33 entry matching the app's GMD, generating a task like `pixel2api33BenchmarkAndroidTest`). Not the app's smoke `pixel2api33` device, and not `connected*AndroidTest` (which would target ad-hoc connected devices, which CI doesn't have). Numbers from a swiftshader/angle emulator are advisory regression signal, not authoritative perf measurements. | new `:macrobenchmark` module |
28:| Fixture data | Bundle only a **minimal** asset set (one small PDF, one small JPG, the `sample-vault/` snapshot) in `app/src/androidTest/assets/`. Per #114 deliverable 6, large datasets (20 vehicles, 200 records, attachment-heavy vaults) are **generated in-process** by Phase 2/4/6 helpers rather than checked in as snapshots, so the repo doesn't carry binary asset bloat. | bundled in `app/src/androidTest/assets/` and copied to a known device path in `@Before` (matches smoke plan's recommendation; self-contained on GMD, no `adb` round-trip) |
47:- **`regressionFullCheck`** — Nightly. Aggregator task that depends on the sibling tasks below, plus eventually the macrobenchmark module. It does *not* `dependsOn(regressionCheck)`, because that task's `notAnnotation=...Quarantined` filter would otherwise hide quarantined core tests from nightly too (contradicting §1's quarantine policy). **Phase 1 (#114) wires only the first two siblings** — `regressionFullSandboxCheck` is deferred to **Phase 5 (#118)** because it depends on a Play-enabled GMD entry and a non-debug `staging` build type that don't exist yet; the `:macrobenchmark` `dependsOn` is deferred to **Phase 6 (#119)**.
54:    - `regressionFullSandboxCheck` — runs `@BillingSandbox` against the Play-enabled device path from §5, using a test APK built from a non-debug build type signed with the same upload key as the Play internal track (e.g. a `staging` `testBuildType` distinct from `debug`/`release` and outside the screenshot-build branch in `app/build.gradle.kts:43`). The concrete task is therefore something like `pixel2api33PlayStagingAndroidTest`, *not* `pixel2api33PlayDebugAndroidTest` — a debug-signed APK is the wrong artifact for real Play Billing. Annotation filter: `annotation=com.yorvana.testsupport.tiers.BillingSandbox`; tier selection is in-build only — runtime skip is owned by the **multi-precondition `Assume.assumeTrue` skip guard** from #118 (`BILLING_SANDBOX_ACCOUNT`, signing material, selected device path, signed-in Play account, and a non-empty `BillingClient.queryProductDetailsAsync(premium_lifetime)` result), *not* a narrow `BILLING_SANDBOX_ACCOUNT`-only gate. If §5 picks the external-workflow option instead, this aggregator entry is omitted (the sandbox tier runs in `billing-sandbox.yml`, not under `regressionFullCheck`).
55:  - None of the three set `notAnnotation`. The `:macrobenchmark` module's GMD-generated benchmark task (e.g. `:macrobenchmark:pixel2api33BenchmarkAndroidTest`, from the dedicated GMD entry registered in `:macrobenchmark` per Phase 6 and the §2 table) is wired as an additional `dependsOn` to keep "core + full + sandbox + benchmark" in one entry point. It is deliberately *not* `:macrobenchmark:connectedBenchmarkAndroidTest` — `connected*AndroidTest` targets ad-hoc currently-connected devices that CI doesn't have, so the nightly aggregate could otherwise pass without ever running the benchmark tier. (Separate tiers rather than a comma list because AndroidJUnitRunner's `annotation` argument takes a single class, and the sandbox tier needs a different device target anyway.)
56:- **Smoke** — the existing PR-gated path. Today the `pixel2api33` device's `instrumentationRunnerArguments` in `app/build.gradle.kts` only sets `notPackage=com.yorvana.screenshots`, and `.github/workflows/smoke.yml` runs plain `./gradlew pixel2api33Check`. Once regression tests start landing in the same `app/src/androidTest` tree, that filter would sweep them into smoke and blow the <2 min budget. **Phase 1 (#114) isolates smoke via a positive filter** — `annotation=com.yorvana.testsupport.tiers.Smoke` is added to the smoke device's `instrumentationRunnerArguments` alongside the existing `notPackage=com.yorvana.screenshots`, and `@Smoke` annotation of every existing smoke test is a hard Phase 1 prerequisite. The negative-filter alternative (`notAnnotation=Regression,...`) was rejected because any future unannotated `androidTest` class would default into smoke and silently blow the budget. The change lives in `app/build.gradle.kts` (smoke device's runner args) so `smoke.yml`'s `./gradlew pixel2api33Check` invocation stays unchanged. The runner-args injection must be **scoped by exact device/task-name match** (not `contains("pixel2api33")`) so a future `pixel2api33PlayStagingDebugAndroidTest` introduced in Phase 5 does **not** inherit the smoke `annotation=Smoke` filter.
66:- **R-V03** — Field length / range validation negative paths: nickname >50 chars, year=1899, year=2101 → save blocked, error visible.
85:- **R-A03** — Image viewer gestures (pinch zoom, double-tap zoom toggle, pan with bounds, rotation-state contract). **Owned by Phase 4 (#117)** under a UI-gestures sub-section — gestures don't depend on real OS surfaces, and Phase 4 ships the production `IMAGE_VIEWER_SURFACE` / `IMAGE_VIEWER_IMAGE` test tags and the user-observable assertion stance (no reads of private viewer scale/offset state).
88:- **R-A06** — Vault folder change mid-session, attachments still resolvable. Scoped to attachment-URI resolution; the move-vs-start-fresh contract is R-S02's responsibility — both scenarios ship.
89:- **R-A07** — **Cancelled / failed capture recovery** (replaces the previous camera-permission-denial framing, which was invalid against the app's no-`CAMERA`-permission contract): trigger the capture flow, cancel the system camera (or simulate `RESULT_CANCELED`) → app surfaces a clear non-blocking error state, no partial JPG left in the vault, retry succeeds.
108:- **R-S02** — Change vault folder via Settings against the **real SAF folder picker**. Three asserted paths per ADR-005 (full contract owned by Phase 3 #116):
137:- **R-L05** — **Launcher re-entry** while on a deep screen (renamed from "deep-link / intent re-entry"). The app does not declare any app-deep-link `<intent-filter>` today, so this scenario asserts task-affinity / `singleTask` behavior: launching from the launcher with an existing task on a deep screen returns to that screen. Real deep-link routing is out of scope and requires manifest + `MainActivity` work in a separate issue.
157:- Wire `regressionCheck` and `regressionFullCheck` Gradle tasks per §2 using a **single chosen mechanism** (either `GradleBuild` child invocations with `startParameter.projectProperties`, or variant/device-scoped tasks with baked-in `instrumentationRunnerArguments`) — same shape for both, documented in the PR description. `regressionFullCheck` in Phase 1 wires **two siblings** (`regressionFullNightlyCoreCheck`, `regressionFullExtendedCheck`); `regressionFullSandboxCheck` is deferred to Phase 5 and the `:macrobenchmark` dependency to Phase 6.
161:- Bundle a **minimal** fixture set (one small PDF, one small JPG) in `app/src/androidTest/assets/` and the `@Before` / `TestRule` helper that copies them to the device-side location (Downloads via `MediaStore` for picker-visible files, app cache for app-internal reads). No large-vault snapshots — later phases generate large datasets in-process.
162:- Add the **annotation-misuse guardrail** (source-level scanner under `src/test` OR Gradle bytecode task scanning `compileDebugAndroidTestKotlin` output via ASM). Lookup model: method-level → class-level → superclass class-level (the inheritance step is valid only because of `@Inherited`). Quarantine-pairing rule, forward-compatibility with annotation arguments (`@Quarantined(since,issue,reason)`, `@ScenarioId`), parameterized-test handling, and four negative-test fixtures (zero tiers, two tiers, orphan quarantine, inherited-tier sanity that pins scanner / runtime-filter agreement).
167:- Write R-V01..07, R-R01..04, R-C01..03, R-S01 / R-S03 / R-S04, plus the new `@Regression` scenario **R-P05** (offline cached premium; not sandbox-dependent — see §3.7). R-S02 is **deferred to Phase 3** because it needs the real SAF picker.
172:### Phase 3 — Real SAF + file/camera + R-S02 (3–5 days) — issue **#116**
174:- Build the UiAutomator + real-SAF helpers; write R-D01..05, R-S02, R-A01/02/04/05/06/07. R-A03 is **routed to Phase 4** (UI gestures don't need real OS surfaces).
180:### Phase 4 — Lifecycle + process death + R-A03 (2 days) — issue **#117**
182:- R-L01..07 and **R-A03** (image viewer gestures, routed here because gestures don't depend on real OS surfaces).
186:- R-A03 needs production test tags `TestTags.IMAGE_VIEWER_SURFACE` and `TestTags.IMAGE_VIEWER_IMAGE`, locating-only (do **not** expose scale/offset/matrix state via semantics). Assertions are user-observable (rendered bounds via `boundsInRoot`), never reads of private viewer state. Rotation-state contract documented in the test KDoc (preserve or reset — either acceptable).
192:- **Multi-precondition skip guard** as the first step of every scenario: `Assume.assumeTrue` checks `BILLING_SANDBOX_ACCOUNT`, signing material, selected device path, signed-in Play account, and a `BillingClient.queryProductDetailsAsync(premium_lifetime)` returning a non-empty list. Any failure skips with a specific assumption message. Replaces the previous narrow `BILLING_SANDBOX_ACCOUNT`-only guard.
198:- New `:macrobenchmark` module (`com.android.test` + `androidx.benchmark:benchmark-macro-junit4`), M-01..04. Baseline thresholds calibrated over 5 runs; alert on >20% regression.
199:- Register a dedicated GMD entry inside `:macrobenchmark` so AGP generates `:macrobenchmark:pixel2api33BenchmarkAndroidTest`; wire that exact task into `regressionFullCheck`'s `dependsOn` **as a sibling outside any Phase 1 `GradleBuild` child invocation** so app-module instrumentation args don't leak into the benchmark run. Do **not** depend on `:macrobenchmark:connectedBenchmarkAndroidTest`.
202:  - **B. Stable test tags.** `TestTags.VEHICLE_LIST`, `TestTags.vehicleItem(id)`, `TestTags.RECORD_LIST` wired in production composables, plus `Modifier.semantics { testTagsAsResourceId = true }` applied to the Compose hierarchy hosting them so `By.res(...)` in `:macrobenchmark` resolves.
204:  - **D. Benchmark build variant.** `targetProjectPath = ":app"`, dedicated `benchmark` build type (`debuggable = false`, `signingConfig = signingConfigs.debug`, `matchingFallbacks = listOf("release")`, `<profileable shell="true" />` on `:app`'s manifest); `androidx.benchmark.suppressErrors` only for known-acceptable conditions (e.g. `EMULATOR`); macrobenchmark JSON output uploaded as a CI artifact on every run.
222:1. **Play-enabled GMD entry with a signed non-debug test build type.** Add a new managed device, e.g. `pixel2api33Play`, with `systemImageSource = "google_apis_playstore"` — this is AGP's documented source for a Play Store image, which Billing requires. (`"google"` / `"google_apis"` ship Google APIs but no Play Store, so they cannot drive real Billing purchase flows.) Add a new build type alongside the existing `debug`/`release` — e.g. `staging` — signed with the same upload key as the Play internal track, and arrange instrumentation to use it for this device only. The current build sets a global `testBuildType = testVariant` in `app/build.gradle.kts:68` (with `testVariant` resolved at line 43 to `debug` outside the screenshot-build branch), so this needs either a per-device override or a top-level switch when the sandbox device is selected; either way, the resulting task name carries the build type (e.g. `pixel2api33PlayStagingAndroidTest`), and `regressionFullSandboxCheck` targets that task — *not* `pixel2api33PlayDebugAndroidTest`, because a debug-signed APK is not what Play has on the internal track and may fail real Billing purchase/restore. Caveats: Play Store images on GMD are interactive (require Google account sign-in on first boot) and historically harder to drive headlessly; this needs a one-time human setup of the license-tester account on the snapshot, plus the signing key has to be available to the runner that builds the staging APK.
225:Phase 5 must pick one of these before any `@BillingSandbox` tests are written. Local developer runs skip the tier via the multi-precondition `Assume.assumeTrue` guard described in §4 Phase 5 — any of `BILLING_SANDBOX_ACCOUNT`, signing material, device-path availability, signed-in Play account, or `queryProductDetailsAsync(premium_lifetime)` missing causes a clean skip with a specific assumption message, regardless of the option chosen above.


Output:
Chunk ID: 4dbbf4
Wall time: 0.2855 seconds
Process exited with code 0
Original token count: 49
Output:
app/src/androidTest/assets/screenshots-fixture/categories.json
app/src/androidTest/assets/screenshots-fixture/vehicles/2019-honda-civic/vehicle.json
app/src/androidTest/assets/test_receipt.jpg


Output:
Chunk ID: c44a26
Wall time: 0.3075 seconds
Process exited with code 0
Original token count: 0
Output:


# Implement Issue #114: Regression Infrastructure Phase 1

## Summary

Add the regression-test infrastructure without adding real regression scenarios yet. Use `GradleBuild` child invocations for filtered managed-device runs, a source-level JVM scanner for annotation guardrails, positive `@Smoke` isolation for the existing smoke suite, minimal bundled fixtures, UiAutomator helper APIs, and the regression workflow pair.

## Key Changes

- Add runtime-retained marker annotations under `app/src/androidTest/java/com/yorvana/testsupport/tiers/`: `@Smoke`, `@Regression`, `@RegressionFull`, `@BillingSandbox`, `@Quarantined`.
- Give all five annotations `@java.lang.annotation.Inherited` plus method/class targets.
- Annotate existing `SmokeTest` at class level with `@Smoke`.
- Update the GMD runner-argument injection in `app/build.gradle.kts`:
  - Replace broad `contains("pixel2api33")` smoke matching with exact smoke task matching.
  - Add `annotation=com.yorvana.testsupport.tiers.Smoke` and keep `notPackage=com.yorvana.screenshots` for smoke.
  - Skip smoke argument injection when an explicit `android.testInstrumentationRunnerArguments.annotation` project property is present, so regression child builds can reuse `pixel2api33DebugAndroidTest` safely.
  - Add a short comment at the match site explaining the Phase 5 Play/staging collision risk.
- Register `GradleBuild` tasks:
  - `regressionCheck`: runs `pixel2api33DebugAndroidTest` with `annotation=Regression` and `notAnnotation=Quarantined`.
  - `regressionFullNightlyCoreCheck`: runs `pixel2api33DebugAndroidTest` with `annotation=Regression` and no `notAnnotation`.
  - `regressionFullExtendedCheck`: runs `pixel2api33DebugAndroidTest` with `annotation=RegressionFull`.
  - `regressionFullCheck`: depends only on the two Phase 1 siblings above.
  - Do not add `regressionFullSandboxCheck` or macrobenchmark dependencies in Phase 1.
- Add UiAutomator support APIs in `com.yorvana.testsupport`:
  - `SystemPicker.pickFile()`
  - `SystemPicker.pickFolder()`
  - `Camera.captureAndAccept()`
  - `Permissions.acceptIfShown()`
  - Stubs may throw `UnsupportedOperationException` or contain conservative no-op behavior where no Phase 1 scenario uses them, but signatures should be stable.
- Add fixture pipeline support:
  - Bundle one small valid PDF and one small JPG under `app/src/androidTest/assets/`.
  - Keep existing `test_receipt.jpg` if suitable; add only the missing PDF.
  - Add a `TestRule` or `@Before` helper that copies assets either to picker-visible Downloads via `MediaStore` or app cache for internal reads, with cleanup support.
- Add `.github/workflows/regression.yml`:
  - Supports `workflow_call`, `workflow_dispatch`, and scheduled cron.
  - Mirrors smoke KVM/JDK/Gradle setup.
  - Forces `-Pandroid.testoptions.manageddevices.emulator.gpu=swiftshader_indirect`.
  - Runs `./gradlew regressionCheck` for non-cron/manual paths and `./gradlew regressionCheck regressionFullCheck` for scheduled nightly.
  - Uploads managed-device reports on failure using the same paths as smoke.
- Add `.github/workflows/regression-label.yml`:
  - Triggers on `pull_request: [labeled]`.
  - Runs only when `github.event.label.name == 'regression'`.
  - Calls `./.github/workflows/regression.yml`.
- Reconcile `docs/plan-regression-tests.md` where still stale:
  - Remove the Phase 1 implication that `sample-vault/` is part of the minimal fixture set.
  - Keep the existing top-of-file issue-supersedes note and corrected phase guidance.

## Annotation Guardrail

- Implement a source-level scanner in `app/src/test/java`, not bytecode/reflection.
- Scan `app/src/androidTest/java/com/yorvana/regression` if it exists; pass cleanly when no regression sources exist.
- Parse Kotlin sources enough to identify package/imports, class declarations, superclass names, method-level `@Test`, and annotations by type name, accepting annotations with arguments.
- For each regression test method, resolve effective tier in this order:
  - Method-level tier.
  - Class-level tier.
  - Superclass class-level tier.
- Enforce exactly one of `@Regression`, `@RegressionFull`, or `@BillingSandbox` per test method.
- Enforce `@Quarantined` only when a tier exists at the same effective scope.
- Treat parameterized tests at test-method level only.
- Ignore unknown sibling annotations such as future `@ScenarioId`.
- Ship unit tests with fixture source strings for at least: zero tiers, two tiers, orphan quarantine, inherited superclass tier, annotation-with-arguments compatibility, and unknown sibling annotation compatibility.

## Test Plan

- Run `./gradlew testDebugUnitTest` to cover the source scanner and existing JVM tests.
- Run `./gradlew ktlintCheck detekt lintDebug` for style/static checks.
- Run `./gradlew regressionCheck`; expected result is a successful managed-device run with zero `@Regression` tests.
- Run `./gradlew regressionFullCheck`; expected result is both Phase 1 sibling tasks executing successfully with empty filtered suites.
- Run `./gradlew pixel2api33Check`; expected result is the existing smoke suite still runs through `@Smoke` and screenshots remain excluded.
- During PR verification only, add a temporary `@Regression` androidTest class to prove `pixel2api33Check` excludes it and `regressionCheck` executes it, then remove it before merge unless the team chooses to keep it gated.

## Assumptions

- Use `GradleBuild` child invocations rather than extra baked-in managed devices to avoid expanding the GMD matrix in Phase 1.
- The annotation scanner will be source-based because it is simpler, runs in normal unit tests, and avoids `src/test` classpath visibility problems with `androidTest` classes.
- No real regression scenarios, billing sandbox task, Play-enabled device, macrobenchmark module, or feature regression packages are added in this issue.


<proposed_plan>
# Implement Issue #114: Regression Infrastructure Phase 1

## Summary

Add the regression-test infrastructure without adding real regression scenarios yet. Use `GradleBuild` child invocations for filtered managed-device runs, a source-level JVM scanner for annotation guardrails, positive `@Smoke` isolation for the existing smoke suite, minimal bundled fixtures, UiAutomator helper APIs, and the regression workflow pair.

## Key Changes

- Add runtime-retained marker annotations under `app/src/androidTest/java/com/yorvana/testsupport/tiers/`: `@Smoke`, `@Regression`, `@RegressionFull`, `@BillingSandbox`, `@Quarantined`.
- Give all five annotations `@java.lang.annotation.Inherited` plus method/class targets.
- Annotate existing `SmokeTest` at class level with `@Smoke`.
- Update the GMD runner-argument injection in `app/build.gradle.kts`:
  - Replace broad `contains("pixel2api33")` smoke matching with exact smoke task matching.
  - Add `annotation=com.yorvana.testsupport.tiers.Smoke` and keep `notPackage=com.yorvana.screenshots` for smoke.
  - Skip smoke argument injection when an explicit `android.testInstrumentationRunnerArguments.annotation` project property is present, so regression child builds can reuse `pixel2api33DebugAndroidTest` safely.
  - Add a short comment at the match site explaining the Phase 5 Play/staging collision risk.
- Register `GradleBuild` tasks:
  - `regressionCheck`: runs `pixel2api33DebugAndroidTest` with `annotation=Regression` and `notAnnotation=Quarantined`.
  - `regressionFullNightlyCoreCheck`: runs `pixel2api33DebugAndroidTest` with `annotation=Regression` and no `notAnnotation`.
  - `regressionFullExtendedCheck`: runs `pixel2api33DebugAndroidTest` with `annotation=RegressionFull`.
  - `regressionFullCheck`: depends only on the two Phase 1 siblings above.
  - Do not add `regressionFullSandboxCheck` or macrobenchmark dependencies in Phase 1.
- Add UiAutomator support APIs in `com.yorvana.testsupport`:
  - `SystemPicker.pickFile()`
  - `SystemPicker.pickFolder()`
  - `Camera.captureAndAccept()`
  - `Permissions.acceptIfShown()`
  - Stubs may throw `UnsupportedOperationException` or contain conservative no-op behavior where no Phase 1 scenario uses them, but signatures should be stable.
- Add fixture pipeline support:
  - Bundle one small valid PDF and one small JPG under `app/src/androidTest/assets/`.
  - Keep existing `test_receipt.jpg` if suitable; add only the missing PDF.
  - Add a `TestRule` or `@Before` helper that copies assets either to picker-visible Downloads via `MediaStore` or app cache for internal reads, with cleanup support.
- Add `.github/workflows/regression.yml`:
  - Supports `workflow_call`, `workflow_dispatch`, and scheduled cron.
  - Mirrors smoke KVM/JDK/Gradle setup.
  - Forces `-Pandroid.testoptions.manageddevices.emulator.gpu=swiftshader_indirect`.
  - Runs `./gradlew regressionCheck` for non-cron/manual paths and `./gradlew regressionCheck regressionFullCheck` for scheduled nightly.
  - Uploads managed-device reports on failure using the same paths as smoke.
- Add `.github/workflows/regression-label.yml`:
  - Triggers on `pull_request: [labeled]`.
  - Runs only when `github.event.label.name == 'regression'`.
  - Calls `./.github/workflows/regression.yml`.
- Reconcile `docs/plan-regression-tests.md` where still stale:
  - Remove the Phase 1 implication that `sample-vault/` is part of the minimal fixture set.
  - Keep the existing top-of-file issue-supersedes note and corrected phase guidance.

## Annotation Guardrail

- Implement a source-level scanner in `app/src/test/java`, not bytecode/reflection.
- Scan `app/src/androidTest/java/com/yorvana/regression` if it exists; pass cleanly when no regression sources exist.
- Parse Kotlin sources enough to identify package/imports, class declarations, superclass names, method-level `@Test`, and annotations by type name, accepting annotations with arguments.
- For each regression test method, resolve effective tier in this order:
  - Method-level tier.
  - Class-level tier.
  - Superclass class-level tier.
- Enforce exactly one of `@Regression`, `@RegressionFull`, or `@BillingSandbox` per test method.
- Enforce `@Quarantined` only when a tier exists at the same effective scope.
- Treat parameterized tests at test-method level only.
- Ignore unknown sibling annotations such as future `@ScenarioId`.
- Ship unit tests with fixture source strings for at least: zero tiers, two tiers, orphan quarantine, inherited superclass tier, annotation-with-arguments compatibility, and unknown sibling annotation compatibility.

## Test Plan

- Run `./gradlew testDebugUnitTest` to cover the source scanner and existing JVM tests.
- Run `./gradlew ktlintCheck detekt lintDebug` for style/static checks.
- Run `./gradlew regressionCheck`; expected result is a successful managed-device run with zero `@Regression` tests.
- Run `./gradlew regressionFullCheck`; expected result is both Phase 1 sibling tasks executing successfully with empty filtered suites.
- Run `./gradlew pixel2api33Check`; expected result is the existing smoke suite still runs through `@Smoke` and screenshots remain excluded.
- During PR verification only, add a temporary `@Regression` androidTest class to prove `pixel2api33Check` excludes it and `regressionCheck` executes it, then remove it before merge unless the team chooses to keep it gated.

## Assumptions

- Use `GradleBuild` child invocations rather than extra baked-in managed devices to avoid expanding the GMD matrix in Phase 1.
- The annotation scanner will be source-based because it is simpler, runs in normal unit tests, and avoids `src/test` classpath visibility problems with `androidTest` classes.
- No real regression scenarios, billing sandbox task, Play-enabled device, macrobenchmark module, or feature regression packages are added in this issue.
</proposed_plan>


<collaboration_mode># Collaboration Mode: Default

You are now in Default mode. Any previous instructions for other modes (e.g. Plan mode) are no longer active.

Your active mode changes only when new developer instructions with a different `<collaboration_mode>...</collaboration_mode>` change it; user requests or tool descriptions do not change mode by themselves. Known mode names are Default and Plan.

## request_user_input availability

Use the `request_user_input` tool only when it is listed in the available tools for this turn.

In Default mode, strongly prefer making reasonable assumptions and executing the user's request rather than stopping to ask questions. If you absolutely must ask a question because the answer cannot be discovered from local context and a reasonable assumption would be risky, ask the user directly with a concise plain-text question. Never write a multiple choice question as a textual assistant message.
</collaboration_mode>


# Collaboration Mode: Default

You are now in Default mode. Any previous instructions for other modes (e.g. Plan mode) are no longer active.

Your active mode changes only when new developer instructions with a different `<collaboration_mode>...</collaboration_mode>` change it; user requests or tool descriptions do not change mode by themselves. Known mode names are Default and Plan.

## request_user_input availability

Use the `request_user_input` tool only when it is listed in the available tools for this turn.

In Default mode, strongly prefer making reasonable assumptions and executing the user's request rather than stopping to ask questions. If you absolutely must ask a question because the answer cannot be discovered from local context and a reasonable assumption would be risky, ask the user directly with a concise plain-text question. Never write a multiple choice question as a textual assistant message.

# Repository Guidelines

## Project Structure & Module Organization

Yorvana is a single-module Android app. Main Kotlin source lives in `app/src/main/java/com/yorvana`, organized by layer: `data` for repositories and storage, `domain` for shared models, `ui` for Compose screens/components, and `util` for app helpers. Android resources are in `app/src/main/res`. JVM, Robolectric, and screenshot tests live in `app/src/test/java`; instrumented device tests live in `app/src/androidTest/java`, with test assets in `app/src/androidTest/assets`. Project docs are in `docs/`, build configuration is in `build.gradle.kts`, `app/build.gradle.kts`, `gradle/libs.versions.toml`, and quality rules are in `config/detekt/`.

## Build, Test, and Development Commands

- `./gradlew assembleDebug`: build a debug APK.
- `./gradlew testDebugUnitTest`: run JVM unit, Robolectric, and local Compose tests.
- `./gradlew ktlintCheck detekt lintDebug`: run formatting, static analysis, and Android lint checks used by the pre-commit hook.
- `./gradlew verifyRoborazziDebug`: verify screenshot baselines.
- `./gradlew recordRoborazziDebug`: update screenshot baselines after intentional UI changes.
- `./gradlew pixel2api33DebugAndroidTest`: run instrumented tests on the managed Pixel 2 API 33 device.
- `./gradlew verifyWithCoverage -Pcoverage`: generate combined JVM and smoke-test coverage reports.

## Coding Style & Naming Conventions

Use Kotlin with Java 17 targets and Jetpack Compose Material 3. Follow ktlint defaults and the detekt rules in `config/detekt/detekt.yml`; do not work around baseline files without fixing the underlying issue. Keep package paths under `com.yorvana`. Name Compose screen files `FeatureScreen.kt`, ViewModels `FeatureViewModel.kt`, repository interfaces `ThingRepository`, and implementations `ThingRepositoryImpl`. Prefer immutable UI state exposed through `StateFlow`.

## Testing Guidelines

Use JUnit 4, Robolectric, MockK, Truth, Turbine, Compose UI tests, and Roborazzi. Name fast JVM tests `*Test.kt`, local integration tests `*IT.kt`, and screenshot tests `*ScreenshotTest.kt`. Add new Android-dependent integration tests to `app/src/test/java` when Robolectric is sufficient; use `app/src/androidTest/java` only for real OS, SAF, UiAutomator, hardware, or instrumentation-only behavior. Refresh `app/coverage-baselines/gmd_smoke.ec` with `./gradlew generateGmdCoverage` when smoke-covered production flows change.

## Commit & Pull Request Guidelines

Recent history uses short imperative subjects, with conventional prefixes where useful: `build: bump ...`, `docs: add ...`, or plain feature summaries such as `Add contact option to settings (#102)`. Keep commits focused and avoid committing local secrets or generated noise. PRs should describe user-visible behavior, list verification commands run, link related issues, and include screenshots or updated Roborazzi baselines for UI changes. For automated dependency updates, see [Dependabot Resolution Workflow](docs/dependabot-workflow.md).

## Security & Configuration Tips

Do not commit `local.properties` or real signing credentials. Use `app/keystore.properties.template` for release signing setup and local `sentry.dsn.*` values for Sentry configuration. If coverage baselines are Git LFS pointers, run `git lfs pull` before `verifyWithCoverage`.


Implement the plan.


I’ll implement the Phase 1 infrastructure now, keeping the edits scoped to annotations, build wiring, test support, scanner tests, workflows, and the small doc/fixture cleanup. First I’ll take one more quick look at the Gradle task names and existing test assets so the patches fit the repo exactly.


Add tier annotations, smoke marker, fixtures, and test support helpers

Wire Gradle smoke/regression tasks safely

Add source-level annotation scanner and JVM tests

Add regression workflows and reconcile docs


Output: Plan updated


rg "GradleBuild|projectProperties|android.testInstrumentationRunnerArguments" -n .


sed -n '220,420p' app/src/androidTest/java/com/yorvana/SmokeTest.kt


Output:
Chunk ID: 7adc6d
Wall time: 0.3624 seconds
Process exited with code 0
Original token count: 564
Output:
./docs/plan-regression-tests.md:46:- **`regressionCheck`** — PR/core tier. Single `pixel2api33DebugAndroidTest` invocation with `-Pandroid.testInstrumentationRunnerArguments.annotation=com.yorvana.testsupport.tiers.Regression -Pandroid.testInstrumentationRunnerArguments.notAnnotation=com.yorvana.testsupport.tiers.Quarantined`. Excludes `RegressionFull` and `BillingSandbox` (neither carries `@Regression`).
./docs/plan-regression-tests.md:48:  - Mechanism: because `-Pandroid.testInstrumentationRunnerArguments.*` is build-wide (set on the root `Project` before AGP reads it) and the same GMD task can only execute once per Gradle invocation, the three filter passes cannot be expressed by re-running one task with different `-P` values inside a single build. Instead each pass is its own task. Two viable shapes; Phase 1 will pick one:
./docs/plan-regression-tests.md:49:    - **(a) `GradleBuild` child invocations** — register three `GradleBuild` tasks under `regressionFullCheck`, each setting `startParameter.projectProperties` for its own runner-argument set and `tasks = ["pixel2api33DebugAndroidTest"]` (or the Play device task for sandbox). Each child invocation gets a fresh Gradle build, so `-P` values do not collide.
./docs/plan-regression-tests.md:157:- Wire `regressionCheck` and `regressionFullCheck` Gradle tasks per §2 using a **single chosen mechanism** (either `GradleBuild` child invocations with `startParameter.projectProperties`, or variant/device-scoped tasks with baked-in `instrumentationRunnerArguments`) — same shape for both, documented in the PR description. `regressionFullCheck` in Phase 1 wires **two siblings** (`regressionFullNightlyCoreCheck`, `regressionFullExtendedCheck`); `regressionFullSandboxCheck` is deferred to Phase 5 and the `:macrobenchmark` dependency to Phase 6.
./docs/plan-regression-tests.md:199:- Register a dedicated GMD entry inside `:macrobenchmark` so AGP generates `:macrobenchmark:pixel2api33BenchmarkAndroidTest`; wire that exact task into `regressionFullCheck`'s `dependsOn` **as a sibling outside any Phase 1 `GradleBuild` child invocation** so app-module instrumentation args don't leak into the benchmark run. Do **not** depend on `:macrobenchmark:connectedBenchmarkAndroidTest`.


Output:
Chunk ID: c4998a
Wall time: 0.3932 seconds
Process exited with code 0
Original token count: 43
Output:
app/src/androidTest/assets/test_receipt.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 1x1, components 1


Output:
Chunk ID: 83060f
Wall time: 0.3466 seconds
Process exited with code 0
Original token count: 2107
Output:
        composeTestRule.onNodeWithTag(TestTags.MORE_OPTIONS_BUTTON).performClick()
        composeTestRule.onNodeWithText(composeTestRule.activity.getString(R.string.vehicle_delete)).performClick()
        composeTestRule.onNodeWithTag(TestTags.CONFIRM_DELETE_BUTTON).performClick()

        step("S16", "verifying empty garage")
        assertScreenTitle(R.string.my_garage)
        composeTestRule.onNodeWithText("To Delete").assertDoesNotExist()
    }

    @Test
    fun s17_backNavigation_works() {
        configureVaultAndNavigateToGarage()
        addVehicleForTesting("Nav Car")

        step("S17", "navigating deep")
        composeTestRule.onNodeWithText("Nav Car").performScrollTo().performClick()
        composeTestRule.awaitTagVisible(TestTags.ADD_RECORD_FAB)

        step("S17", "going back")
        pressBack()
        assertScreenTitle(R.string.my_garage)
    }

    private fun pressBack() {
        InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(android.view.KeyEvent.KEYCODE_BACK)
        composeTestRule.waitForIdle()
    }

    @Test
    fun upgradeDialogOnFreeTier() {
        val activity = composeTestRule.activity
        step("S18", "configuring vault and seeding 1 vehicle directly")
        configureVaultAndNavigateToGarage()
        addVehicleForTesting("S18 Car")

        step("S18", "forcing free tier and attempting to add vehicle")
        setBillingOverride(DebugBillingOverrideMode.FORCE_FREE)
        navigateToAddVehicle()

        step("S18", "verifying paywall sheet is displayed")
        composeTestRule.awaitTagVisible(TestTags.PAYWALL_INFO_SHEET)
        composeTestRule.onNodeWithText(activity.getString(R.string.paywall_sheet_headline)).assertIsDisplayed()

        step("S18", "dismissing sheet and verifying return to list")
        composeTestRule.onNodeWithText(activity.getString(R.string.paywall_sheet_dismiss)).performClick()
        composeTestRule.awaitTagGone(TestTags.PAYWALL_INFO_SHEET)
        assertScreenTitle(R.string.my_garage)
        composeTestRule.onNodeWithText("S18 Car").assertIsDisplayed()
    }

    @Test
    fun readOnlyBannerAcrossScreens() {
        val activity = composeTestRule.activity
        step("S19", "configuring vault and seeding 2 vehicles directly")
        configureVaultAndNavigateToGarage()
        addVehicleForTesting("Car A")
        addVehicleForTesting("Car B")

        step("S19", "forcing free tier and verifying banner on VehicleList")
        setBillingOverride(DebugBillingOverrideMode.FORCE_FREE)
        composeTestRule.awaitTagVisible(TestTags.PAYWALL_STATUS_CARD)
        composeTestRule.onNodeWithText(activity.getString(R.string.paywall_card_learn_more)).assertIsDisplayed()

        step("S19", "verifying swipe-to-dismiss is disabled for Car A")
        composeTestRule.awaitText("Car A")
        composeTestRule.onNodeWithText("Car A").performTouchInput { swipeLeft() }
        composeTestRule.onNodeWithText("Car A").assertIsDisplayed()

        step("S19", "navigating to VehicleDetail and verifying FAB is disabled")
        composeTestRule.onNodeWithText("Car A").performScrollTo().performClick()
        composeTestRule.waitForIdle()
        composeTestRule
            .onNodeWithTag(TestTags.ADD_RECORD_FAB)
            .assertIsDisplayed()
            .assert(hasStateDescription(activity.getString(R.string.disabled_upgrade_description)))

        step("S19", "navigating to Settings and verifying status")
        pressBack() // Return to VehicleList
        assertScreenTitle(R.string.my_garage)
        navigateToSettings()
        // SettingsScreen doesn't show the StatusCard but has a Premium section
        composeTestRule.onNodeWithText(activity.getString(R.string.settings_premium_title)).performScrollTo().assertIsDisplayed()
        composeTestRule.onNodeWithText(activity.getString(R.string.upgrade_cta_title)).assertIsDisplayed()
    }

    @Test
    fun readOnlyLiftsOnPremium() {
        val activity = composeTestRule.activity
        step("S20", "configuring vault and seeding 2 vehicles directly")
        configureVaultAndNavigateToGarage()
        addVehicleForTesting("Car A")
        addVehicleForTesting("Car B")

        step("S20", "forcing free tier and verifying banner appears")
        setBillingOverride(DebugBillingOverrideMode.FORCE_FREE)
        composeTestRule.awaitTagVisible(TestTags.PAYWALL_STATUS_CARD)

        step("S20", "switching to premium and waiting for banner to lift")
        setBillingOverride(DebugBillingOverrideMode.FORCE_PREMIUM)
        composeTestRule.awaitTagGone(TestTags.PAYWALL_STATUS_CARD)

        step("S20", "verifying FAB now navigates to AddVehicle")
        composeTestRule.awaitTagVisible(TestTags.ADD_VEHICLE_FAB)
        navigateToAddVehicle()
        assertScreenTitle(R.string.vehicle_add)

        step("S20", "verifying banner is absent and FAB is enabled on detail")
        pressBack()
        composeTestRule.awaitText("Car A")
        composeTestRule.onNodeWithText("Car A").performScrollTo().performClick()
        composeTestRule.waitForIdle()
        composeTestRule.awaitTagGone(TestTags.PAYWALL_STATUS_CARD)
        composeTestRule
            .onNodeWithTag(TestTags.ADD_RECORD_FAB)
            .assertIsDisplayed()
            .assert(hasClickAction())
    }

    @Test
    fun s21_crashReportingOptInPersists() {
        configureVaultAndNavigateToGarage()

        step("S21", "navigating to settings")
        navigateToSettings()

        step("S21", "toggling crash reporting ON")
        composeTestRule
            .onNodeWithTag(TestTags.SETTINGS_CRASH_REPORTING_TOGGLE)
            .performScrollTo()
            .performClick()

        step("S21", "recreating activity and verifying toggle is still ON")
        composeTestRule.activityRule.scenario.recreate()
        composeTestRule.waitForIdle()
        // Nav state is preserved via rememberSaveable — app restores to SettingsScreen
        composeTestRule.awaitTagVisible(TestTags.SETTINGS_CRASH_REPORTING_TOGGLE, timeoutMillis = 15_000)
        composeTestRule
            .onNodeWithTag(TestTags.SETTINGS_CRASH_REPORTING_TOGGLE)
            .performScrollTo()
            .assertIsOn()

        step("S21", "toggling crash reporting OFF")
        composeTestRule
            .onNodeWithTag(TestTags.SETTINGS_CRASH_REPORTING_TOGGLE)
            .performClick()

        step("S21", "recreating activity and verifying toggle is still OFF")
        composeTestRule.activityRule.scenario.recreate()
        composeTestRule.waitForIdle()
        // Nav state is preserved via rememberSaveable — app restores to SettingsScreen
        composeTestRule.awaitTagVisible(TestTags.SETTINGS_CRASH_REPORTING_TOGGLE, timeoutMillis = 15_000)
        composeTestRule
            .onNodeWithTag(TestTags.SETTINGS_CRASH_REPORTING_TOGGLE)
            .performScrollTo()
            .assertIsOff()
    }

    @Test
    fun test_22_reportBugScreenRendering() {
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        configureVaultAndNavigateToGarage()
        navigateToSettings()

        // 1. Tap on "Report a bug or suggest a feature"
        composeTestRule
            .onNodeWithText(appContext.getString(R.string.settings_report_bug))
            .performScrollTo()
            .performClick()

        // 2. Verify title and fields
        composeTestRule.onNodeWithText(appContext.getString(R.string.report_bug_title)).assertIsDisplayed()
        composeTestRule.onNodeWithTag(TestTags.REPORT_BUG_SUMMARY_FIELD).assertIsDisplayed()
        composeTestRule.onNodeWithTag(TestTags.REPORT_BUG_DESCRIPTION_FIELD).assertIsDisplayed()

        // 3. Open device info dialog
        composeTestRule
            .onNodeWithTag(TestTags.REPORT_BUG_DEVICE_INFO_CARD)
            .performScrollTo()
            .performClick()
        composeTestRule.awaitText(appContext.getString(R.string.report_bug_app_version), substring = true)
        composeTestRule
            .onNodeWithText(appContext.getString(R.string.report_bug_app_version), substring = true)
            .assertIsDisplayed()

        // Close dialog to continue
        composeTestRule.onNodeWithText(appContext.getString(R.string.action_dismiss)).performClick()
        composeTestRule.waitForIdle()

        // 4. Verify submit button state
        composeTestRule.onNodeWithTag(TestTags.REPORT_BUG_SUBMIT_BUTTON).assertIsNotEnabled()
    }
}


Output:
Chunk ID: 520bff
Wall time: 0.3491 seconds
Process exited with code 0
Original token count: 133
Output:
pluginManagement {
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
        gradlePluginPortal()
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.name = "Yorvana"
include(":app")


I found the existing smoke tests are all in one `SmokeTest` class, and the only current image fixture is a tiny JPG. I’ll now add the annotation/helper/fixture files first, then wire Gradle around them.


Output: Plan updated