125 lines
4.7 KiB
Dart
125 lines
4.7 KiB
Dart
import 'package:drift/native.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:motorcycle_dash/database/database.dart';
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
test('new rides receive a persisted cloudRideId independent of local id', () async {
|
|
final db = AppDatabase.forTesting(NativeDatabase.memory());
|
|
addTearDown(db.close);
|
|
|
|
final localId = await db.startRide();
|
|
final cloudId = await db.getCloudRideId(localId);
|
|
|
|
expect(cloudId, isNotNull);
|
|
expect(cloudId, startsWith('ride_'));
|
|
expect(cloudId, isNot(localId.toString()));
|
|
|
|
final secondLocalId = await db.startRide();
|
|
final secondCloudId = await db.getCloudRideId(secondLocalId);
|
|
expect(secondCloudId, isNot(cloudId));
|
|
|
|
// Re-reading the same local row returns the exact persisted identity.
|
|
expect(await db.getCloudRideId(localId), cloudId);
|
|
});
|
|
|
|
test('ensureCloudRideId is idempotent', () async {
|
|
final db = AppDatabase.forTesting(NativeDatabase.memory());
|
|
addTearDown(db.close);
|
|
|
|
final localId = await db.startRide();
|
|
final first = await db.ensureCloudRideId(localId);
|
|
final second = await db.ensureCloudRideId(localId);
|
|
|
|
expect(second, first);
|
|
});
|
|
|
|
test('real v5 rides migrate to their legacy MotorCloud identity', () async {
|
|
final connection = NativeDatabase.memory(setup: (rawDb) {
|
|
rawDb.execute('''
|
|
CREATE TABLE rides (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
start_time INTEGER NOT NULL,
|
|
end_time INTEGER,
|
|
distance_miles REAL NOT NULL DEFAULT 0.0,
|
|
top_speed_mph REAL NOT NULL DEFAULT 0.0,
|
|
max_lean_left REAL NOT NULL DEFAULT 0.0,
|
|
max_lean_right REAL NOT NULL DEFAULT 0.0,
|
|
max_accel_g REAL NOT NULL DEFAULT 0.0,
|
|
max_braking_g REAL NOT NULL DEFAULT 0.0,
|
|
best0to60_ms REAL,
|
|
best0to100_ms REAL,
|
|
distance REAL NOT NULL DEFAULT 0.0,
|
|
moving_time INTEGER NOT NULL DEFAULT 0,
|
|
stopped_time INTEGER NOT NULL DEFAULT 0,
|
|
average_speed REAL NOT NULL DEFAULT 0.0,
|
|
top_speed REAL NOT NULL DEFAULT 0.0,
|
|
elevation_gain REAL NOT NULL DEFAULT 0.0,
|
|
elevation_loss REAL NOT NULL DEFAULT 0.0,
|
|
motorcycle_id INTEGER,
|
|
motorcycle_year INTEGER,
|
|
motorcycle_make TEXT,
|
|
motorcycle_model TEXT,
|
|
motorcycle_variant TEXT
|
|
)
|
|
''');
|
|
final start = DateTime.utc(2026, 8, 31, 21, 7, 5);
|
|
rawDb.execute('INSERT INTO rides (id, start_time) VALUES (?, ?)', [42, start.millisecondsSinceEpoch]);
|
|
rawDb.execute('PRAGMA user_version = 5');
|
|
});
|
|
|
|
final db = AppDatabase.forTesting(connection);
|
|
addTearDown(db.close);
|
|
|
|
final migrated = await db.getCloudRideId(42);
|
|
expect(migrated, 'ride_42_20260831_210705');
|
|
|
|
final rows = await db.customSelect('PRAGMA table_info(rides)').get();
|
|
expect(rows.any((row) => row.data['name'] == 'cloud_ride_id'), isTrue);
|
|
|
|
final indexes = await db.customSelect('PRAGMA index_list(rides)').get();
|
|
expect(indexes.any((row) => row.data['name'] == 'rides_cloud_ride_id_idx'), isTrue);
|
|
});
|
|
|
|
test('fresh database creation creates cloud identity column and unique index', () async {
|
|
final db = AppDatabase.forTesting(NativeDatabase.memory());
|
|
addTearDown(db.close);
|
|
|
|
final columns = await db.customSelect('PRAGMA table_info(rides)').get();
|
|
expect(columns.any((row) => row.data['name'] == 'cloud_ride_id'), isTrue);
|
|
|
|
final indexes = await db.customSelect('PRAGMA index_list(rides)').get();
|
|
expect(indexes.any((row) => row.data['name'] == 'rides_cloud_ride_id_idx'), isTrue);
|
|
|
|
final rideId = await db.startRide();
|
|
expect(await db.getCloudRideId(rideId), startsWith('ride_'));
|
|
});
|
|
|
|
test('a restored ride keeps its cloud identity even when its local ID changes', () async {
|
|
const cloudId = 'ride_9f4d8a3e2b1c7d6e5f4a3b2c1d0e9f8a';
|
|
final original = AppDatabase.forTesting(NativeDatabase.memory());
|
|
final restored = AppDatabase.forTesting(NativeDatabase.memory());
|
|
addTearDown(original.close);
|
|
addTearDown(restored.close);
|
|
|
|
final originalId = await original.startRide();
|
|
await original.customStatement(
|
|
'UPDATE rides SET cloud_ride_id = ? WHERE id = ?',
|
|
[cloudId, originalId],
|
|
);
|
|
expect(await original.getCloudRideId(originalId), cloudId);
|
|
|
|
// Insert a dummy ride first so the restored DB assigns a different local ID
|
|
await restored.startRide();
|
|
final restoredId = await restored.startRide();
|
|
await restored.customStatement(
|
|
'UPDATE rides SET cloud_ride_id = ? WHERE id = ?',
|
|
[cloudId, restoredId],
|
|
);
|
|
|
|
expect(restoredId, isNot(originalId));
|
|
expect(await restored.getCloudRideId(restoredId), cloudId);
|
|
});
|
|
}
|