199 lines
6.5 KiB
Dart
199 lines
6.5 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:motorcycle_dash/services/routes/route_models.dart';
|
|
|
|
void main() {
|
|
group('RouteStop & RouteStopType tests', () {
|
|
test('RouteStop serialization round-trip', () {
|
|
const stop = RouteStop(
|
|
id: 'stop-1',
|
|
latitude: 37.7749,
|
|
longitude: -122.4194,
|
|
displayName: 'San Francisco Hub',
|
|
stopType: RouteStopType.origin,
|
|
orderIndex: 0,
|
|
notes: 'Meet at 9 AM',
|
|
);
|
|
|
|
final json = stop.toJson();
|
|
final fromJson = RouteStop.fromJson(json);
|
|
|
|
expect(fromJson.id, equals('stop-1'));
|
|
expect(fromJson.latitude, equals(37.7749));
|
|
expect(fromJson.longitude, equals(-122.4194));
|
|
expect(fromJson.displayName, equals('San Francisco Hub'));
|
|
expect(fromJson.stopType, equals(RouteStopType.origin));
|
|
expect(fromJson.orderIndex, equals(0));
|
|
expect(fromJson.notes, equals('Meet at 9 AM'));
|
|
expect(fromJson, equals(stop));
|
|
});
|
|
|
|
test('RouteStop copyWith preserves and modifies fields', () {
|
|
const stop = RouteStop(
|
|
id: 'stop-1',
|
|
latitude: 37.7749,
|
|
longitude: -122.4194,
|
|
displayName: 'SF',
|
|
stopType: RouteStopType.origin,
|
|
orderIndex: 0,
|
|
);
|
|
|
|
final updated = stop.copyWith(
|
|
displayName: 'SF City Hall',
|
|
orderIndex: 1,
|
|
stopType: RouteStopType.waypoint,
|
|
);
|
|
|
|
expect(updated.id, equals('stop-1'));
|
|
expect(updated.displayName, equals('SF City Hall'));
|
|
expect(updated.orderIndex, equals(1));
|
|
expect(updated.stopType, equals(RouteStopType.waypoint));
|
|
expect(updated.latitude, equals(37.7749));
|
|
});
|
|
|
|
test('RouteStopType labels', () {
|
|
expect(RouteStopType.origin.label, equals('Start / Origin'));
|
|
expect(RouteStopType.waypoint.label, equals('Waypoint'));
|
|
expect(RouteStopType.fuel.label, equals('Fuel Stop'));
|
|
expect(RouteStopType.rest.label, equals('Rest Area'));
|
|
expect(RouteStopType.food.label, equals('Food & Drink'));
|
|
expect(RouteStopType.scenic.label, equals('Scenic Overlook'));
|
|
expect(RouteStopType.regroup.label, equals('Regroup Point'));
|
|
expect(RouteStopType.destination.label, equals('Destination'));
|
|
});
|
|
});
|
|
|
|
group('MotorSignalRoute domain model tests', () {
|
|
final now = DateTime.utc(2026, 9, 4, 12, 0, 0);
|
|
|
|
test('calculates straight-line distance correctly via Haversine', () {
|
|
final route = MotorSignalRoute(
|
|
id: 'route-sf-sj',
|
|
ownerUid: 'alice',
|
|
title: 'SF to San Jose Run',
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
stops: const [
|
|
RouteStop(
|
|
id: 'stop-0',
|
|
latitude: 37.7749,
|
|
longitude: -122.4194,
|
|
displayName: 'SF Start',
|
|
stopType: RouteStopType.origin,
|
|
orderIndex: 0,
|
|
),
|
|
RouteStop(
|
|
id: 'stop-1',
|
|
latitude: 37.4419,
|
|
longitude: -122.1430,
|
|
displayName: 'Palo Alto',
|
|
stopType: RouteStopType.waypoint,
|
|
orderIndex: 1,
|
|
),
|
|
RouteStop(
|
|
id: 'stop-2',
|
|
latitude: 37.3382,
|
|
longitude: -121.8863,
|
|
displayName: 'San Jose Finish',
|
|
stopType: RouteStopType.destination,
|
|
orderIndex: 2,
|
|
),
|
|
],
|
|
);
|
|
|
|
expect(route.stops.length, equals(3));
|
|
expect(route.previewPoints.length, equals(3));
|
|
expect(route.totalDistanceMeters, greaterThan(65000));
|
|
expect(route.totalDistanceMeters, lessThan(85000));
|
|
expect(route.distanceMiles, greaterThan(40));
|
|
expect(route.distanceMiles, lessThan(55));
|
|
expect(route.formattedDistanceMiles, contains('mi'));
|
|
expect(route.formattedDistanceKm, contains('km'));
|
|
});
|
|
|
|
test('empty or single stop route has 0 distance', () {
|
|
final emptyRoute = MotorSignalRoute(
|
|
id: 'route-empty',
|
|
ownerUid: 'alice',
|
|
title: 'Empty Route',
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
stops: const [],
|
|
);
|
|
expect(emptyRoute.totalDistanceMeters, equals(0.0));
|
|
expect(emptyRoute.distanceMiles, equals(0.0));
|
|
|
|
final singleStopRoute = MotorSignalRoute(
|
|
id: 'route-single',
|
|
ownerUid: 'alice',
|
|
title: 'Single Stop Route',
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
stops: const [
|
|
RouteStop(
|
|
id: 'stop-0',
|
|
latitude: 37.7749,
|
|
longitude: -122.4194,
|
|
displayName: 'Solo',
|
|
stopType: RouteStopType.origin,
|
|
orderIndex: 0,
|
|
),
|
|
],
|
|
);
|
|
expect(singleStopRoute.totalDistanceMeters, equals(0.0));
|
|
expect(singleStopRoute.distanceMiles, equals(0.0));
|
|
});
|
|
|
|
test('MotorSignalRoute serialization round-trip', () {
|
|
final route = MotorSignalRoute(
|
|
id: 'route-1',
|
|
ownerUid: 'alice',
|
|
title: 'Skyline Ridge',
|
|
description: 'Twisty canyon ride',
|
|
visibility: RouteVisibility.groupOnly,
|
|
source: RouteSource.planner,
|
|
attachedGroupRideId: 'group-ride-123',
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
stops: const [
|
|
RouteStop(
|
|
id: 'stop-1',
|
|
latitude: 37.4,
|
|
longitude: -122.2,
|
|
displayName: 'Alice\'s',
|
|
stopType: RouteStopType.origin,
|
|
orderIndex: 0,
|
|
),
|
|
RouteStop(
|
|
id: 'stop-2',
|
|
latitude: 37.2,
|
|
longitude: -122.1,
|
|
displayName: 'Vista Point',
|
|
stopType: RouteStopType.destination,
|
|
orderIndex: 1,
|
|
),
|
|
],
|
|
);
|
|
|
|
final json = route.toJson();
|
|
final fromJson = MotorSignalRoute.fromJson(json);
|
|
|
|
expect(fromJson.id, equals('route-1'));
|
|
expect(fromJson.ownerUid, equals('alice'));
|
|
expect(fromJson.title, equals('Skyline Ridge'));
|
|
expect(fromJson.description, equals('Twisty canyon ride'));
|
|
expect(fromJson.visibility, equals(RouteVisibility.groupOnly));
|
|
expect(fromJson.source, equals(RouteSource.planner));
|
|
expect(fromJson.attachedGroupRideId, equals('group-ride-123'));
|
|
expect(fromJson.stops.length, equals(2));
|
|
expect(fromJson.stops[0].displayName, equals('Alice\'s'));
|
|
expect(fromJson.stops[1].displayName, equals('Vista Point'));
|
|
});
|
|
|
|
test('RouteVisibility labels', () {
|
|
expect(RouteVisibility.private.label, equals('Private'));
|
|
expect(RouteVisibility.groupOnly.label, equals('Group Ride Only'));
|
|
expect(RouteVisibility.public.label, equals('Public'));
|
|
});
|
|
});
|
|
}
|