Refresh the Flutter snapshot: v3 tickets V3-04 through V3-16, plus a fresh installable APK
V3-04 through V3-07, V3-10, V3-16 shipped complete; V3-11/V3-12/V3-14 shipped code-complete pending device/account verification; V3-08/V3-09 deferred behind a new V3-17 (self-hosted OSRM investigation). 316 tests passing, up from 221. The APK is a fresh release build (debug-signed, no release signing config exists yet) with two build fixes applied: core library desugaring enabled for flutter_local_notifications, and sentry_flutter bumped to 9.27.0 (8.14.2's bundled Kotlin plugin was incompatible with this project's Kotlin 2.4.0 toolchain).
This commit is contained in:
133
rippr-flutter-src/test/route_plan_repository_test.dart
Normal file
133
rippr-flutter-src/test/route_plan_repository_test.dart
Normal file
@@ -0,0 +1,133 @@
|
||||
import 'package:drift/drift.dart' show driftRuntimeOptions;
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:rippr/src/data/database.dart';
|
||||
import 'package:rippr/src/data/route_plan_repository.dart';
|
||||
import 'package:rippr/src/data/trip_repository.dart';
|
||||
import 'package:rippr/src/geo/geo.dart' as geo;
|
||||
|
||||
/// V3-07: mirrors trip_repository_test.dart's shape -- in-memory Drift, real repository,
|
||||
/// no mocks. A route plan has no state machine, so most of what is tested here is
|
||||
/// straight-line distance staying correct after every mutation.
|
||||
void main() {
|
||||
late AppDatabase db;
|
||||
late RoutePlanRepository routes;
|
||||
late TripRepository trips;
|
||||
|
||||
setUp(() {
|
||||
driftRuntimeOptions.dontWarnAboutMultipleDatabases = true;
|
||||
db = AppDatabase(NativeDatabase.memory());
|
||||
routes = RoutePlanRepository(db);
|
||||
trips = TripRepository(db);
|
||||
});
|
||||
|
||||
tearDown(() async => db.close());
|
||||
|
||||
test('a new route plan has no waypoints and zero distance', () async {
|
||||
final id = await routes.createRoutePlan(1000);
|
||||
final plan = await routes.routePlanById(id);
|
||||
|
||||
expect(plan, isNotNull);
|
||||
expect(plan!.distanceM, 0.0);
|
||||
expect(await routes.waypointsFor(id), isEmpty);
|
||||
});
|
||||
|
||||
test('adding waypoints appends in order and updates distance live', () async {
|
||||
final id = await routes.createRoutePlan(1000);
|
||||
|
||||
await routes.addWaypoint(id, 51.0, -114.0);
|
||||
await routes.addWaypoint(id, 51.01, -114.0);
|
||||
await routes.addWaypoint(id, 51.02, -114.0);
|
||||
|
||||
final waypoints = await routes.waypointsFor(id);
|
||||
expect(waypoints.map((w) => w.ordinal), [0, 1, 2]);
|
||||
|
||||
final expected = geo.pathLengthMeters([
|
||||
for (final w in waypoints) geo.LatLon(w.latitude, w.longitude),
|
||||
]);
|
||||
final plan = await routes.routePlanById(id);
|
||||
expect(plan!.distanceM, expected);
|
||||
expect(expected, greaterThan(0));
|
||||
});
|
||||
|
||||
test('moving a waypoint updates distance', () async {
|
||||
final id = await routes.createRoutePlan(1000);
|
||||
await routes.addWaypoint(id, 51.0, -114.0);
|
||||
await routes.addWaypoint(id, 51.01, -114.0);
|
||||
final before = (await routes.routePlanById(id))!.distanceM;
|
||||
|
||||
final target = (await routes.waypointsFor(id)).last;
|
||||
await routes.moveWaypoint(id, target.id, 52.0, -114.0);
|
||||
|
||||
final after = (await routes.routePlanById(id))!.distanceM;
|
||||
expect(after, isNot(before));
|
||||
});
|
||||
|
||||
test('deleting a waypoint closes the ordinal gap and updates distance', () async {
|
||||
final id = await routes.createRoutePlan(1000);
|
||||
await routes.addWaypoint(id, 51.0, -114.0);
|
||||
await routes.addWaypoint(id, 51.01, -114.0);
|
||||
await routes.addWaypoint(id, 51.02, -114.0);
|
||||
|
||||
final middle = (await routes.waypointsFor(id))[1];
|
||||
await routes.deleteWaypoint(id, middle.id);
|
||||
|
||||
final remaining = await routes.waypointsFor(id);
|
||||
expect(remaining.length, 2);
|
||||
expect(remaining.map((w) => w.ordinal), [0, 1]);
|
||||
|
||||
final expected = geo.pathLengthMeters([
|
||||
for (final w in remaining) geo.LatLon(w.latitude, w.longitude),
|
||||
]);
|
||||
expect((await routes.routePlanById(id))!.distanceM, expected);
|
||||
});
|
||||
|
||||
test('reordering renumbers ordinals and leaves distance internally consistent',
|
||||
() async {
|
||||
final id = await routes.createRoutePlan(1000);
|
||||
await routes.addWaypoint(id, 51.0, -114.0);
|
||||
await routes.addWaypoint(id, 51.01, -114.0);
|
||||
await routes.addWaypoint(id, 51.02, -114.0);
|
||||
|
||||
await routes.reorderWaypoint(id, 0, 2);
|
||||
|
||||
final reordered = await routes.waypointsFor(id);
|
||||
expect(reordered.map((w) => w.ordinal), [0, 1, 2]);
|
||||
expect(reordered.map((w) => w.latitude), [51.01, 51.02, 51.0]);
|
||||
});
|
||||
|
||||
test('renaming updates the row', () async {
|
||||
final id = await routes.createRoutePlan(1000);
|
||||
await routes.renameRoutePlan(id, 'Coast loop');
|
||||
expect((await routes.routePlanById(id))!.name, 'Coast loop');
|
||||
});
|
||||
|
||||
test('deleting a route plan cascades to its waypoints', () async {
|
||||
final id = await routes.createRoutePlan(1000);
|
||||
await routes.addWaypoint(id, 51.0, -114.0);
|
||||
await routes.addWaypoint(id, 51.01, -114.0);
|
||||
|
||||
await routes.deleteRoutePlan(id);
|
||||
|
||||
expect(await routes.routePlanById(id), isNull);
|
||||
expect(await db.waypointsForRoute(id), isEmpty);
|
||||
});
|
||||
|
||||
test('route plans never appear alongside trips and never affect ride totals',
|
||||
() async {
|
||||
await routes.createRoutePlan(1000, name: 'Plan A');
|
||||
final routeId = await routes.createRoutePlan(2000, name: 'Plan B');
|
||||
await routes.addWaypoint(routeId, 51.0, -114.0);
|
||||
await routes.addWaypoint(routeId, 52.0, -114.0);
|
||||
|
||||
final h = await trips.startTrip(3000);
|
||||
await trips.appendPoints([]);
|
||||
await trips.completeTrip(4000);
|
||||
|
||||
final completedTrips = await trips.db.watchCompletedTrips().first;
|
||||
expect(completedTrips.length, 1);
|
||||
expect(completedTrips.single.id, h.tripId);
|
||||
// Nothing about a route plan's distance leaked into the trip.
|
||||
expect(completedTrips.single.distanceM, 0.0);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user