236 lines
6.8 KiB
Dart
236 lines
6.8 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:motorcycle_dash/services/routes/navigation_handoff.dart';
|
|
import 'package:motorcycle_dash/services/routes/route_models.dart';
|
|
import 'package:motorcycle_dash/services/routes/route_provider.dart';
|
|
import 'package:motorcycle_dash/services/routes/route_service.dart';
|
|
|
|
void main() {
|
|
group('RouteService validation tests', () {
|
|
final service = RouteService(firestore: null);
|
|
|
|
test('validates route title length (minimum 3 characters)', () async {
|
|
expect(
|
|
() => service.saveRoute(
|
|
title: 'Hi',
|
|
ownerUid: 'alice',
|
|
stops: [],
|
|
),
|
|
throwsA(isA<ArgumentError>().having(
|
|
(e) => e.message,
|
|
'message',
|
|
contains('between 3 and 80 characters'),
|
|
)),
|
|
);
|
|
});
|
|
|
|
test('validates route title length (maximum 80 characters)', () async {
|
|
final longTitle = 'A' * 81;
|
|
expect(
|
|
() => service.saveRoute(
|
|
title: longTitle,
|
|
ownerUid: 'alice',
|
|
stops: [],
|
|
),
|
|
throwsA(isA<ArgumentError>().having(
|
|
(e) => e.message,
|
|
'message',
|
|
contains('between 3 and 80 characters'),
|
|
)),
|
|
);
|
|
});
|
|
|
|
test('validates maximum stops technical cap (25 stops)', () async {
|
|
final stops = List.generate(
|
|
26,
|
|
(i) => RouteStop(
|
|
id: 'stop-$i',
|
|
latitude: 37.0 + i * 0.01,
|
|
longitude: -122.0,
|
|
displayName: 'Stop $i',
|
|
stopType: RouteStopType.waypoint,
|
|
orderIndex: i,
|
|
),
|
|
);
|
|
|
|
expect(
|
|
() => service.saveRoute(
|
|
title: 'Too Many Stops Route',
|
|
ownerUid: 'alice',
|
|
stops: stops,
|
|
),
|
|
throwsA(isA<ArgumentError>().having(
|
|
(e) => e.message,
|
|
'message',
|
|
contains('cannot exceed 25 stops'),
|
|
)),
|
|
);
|
|
});
|
|
|
|
test('validates stop coordinates bounds', () async {
|
|
final invalidLatStop = [
|
|
const RouteStop(
|
|
id: 'stop-bad-lat',
|
|
latitude: 95.0,
|
|
longitude: -122.0,
|
|
displayName: 'Bad Lat',
|
|
stopType: RouteStopType.origin,
|
|
orderIndex: 0,
|
|
),
|
|
];
|
|
|
|
expect(
|
|
() => service.saveRoute(
|
|
title: 'Invalid Coordinates Route',
|
|
ownerUid: 'alice',
|
|
stops: invalidLatStop,
|
|
),
|
|
throwsA(isA<ArgumentError>().having(
|
|
(e) => e.message,
|
|
'message',
|
|
contains('invalid coordinates'),
|
|
)),
|
|
);
|
|
|
|
final invalidLngStop = [
|
|
const RouteStop(
|
|
id: 'stop-bad-lng',
|
|
latitude: 37.0,
|
|
longitude: -185.0,
|
|
displayName: 'Bad Lng',
|
|
stopType: RouteStopType.origin,
|
|
orderIndex: 0,
|
|
),
|
|
];
|
|
|
|
expect(
|
|
() => service.saveRoute(
|
|
title: 'Invalid Coordinates Route',
|
|
ownerUid: 'alice',
|
|
stops: invalidLngStop,
|
|
),
|
|
throwsA(isA<ArgumentError>().having(
|
|
(e) => e.message,
|
|
'message',
|
|
contains('invalid coordinates'),
|
|
)),
|
|
);
|
|
});
|
|
|
|
test('offline fallback: saveRoute generates valid route object and reindexes stops', () async {
|
|
final inputStops = [
|
|
const RouteStop(
|
|
id: 'stop-b',
|
|
latitude: 37.4,
|
|
longitude: -122.2,
|
|
displayName: 'Midpoint',
|
|
stopType: RouteStopType.waypoint,
|
|
orderIndex: 99,
|
|
),
|
|
const RouteStop(
|
|
id: 'stop-a',
|
|
latitude: 37.7,
|
|
longitude: -122.4,
|
|
displayName: 'Start',
|
|
stopType: RouteStopType.origin,
|
|
orderIndex: 0,
|
|
),
|
|
];
|
|
|
|
final saved = await service.saveRoute(
|
|
title: 'Skyline Ridge',
|
|
description: 'Twisty Sunday Run',
|
|
ownerUid: 'alice',
|
|
visibility: RouteVisibility.groupOnly,
|
|
stops: inputStops,
|
|
);
|
|
|
|
expect(saved.id, startsWith('route_'));
|
|
expect(saved.title, equals('Skyline Ridge'));
|
|
expect(saved.ownerUid, equals('alice'));
|
|
expect(saved.visibility, equals(RouteVisibility.groupOnly));
|
|
expect(saved.stops.length, equals(2));
|
|
expect(saved.stops[0].orderIndex, equals(0));
|
|
expect(saved.stops[1].orderIndex, equals(1));
|
|
});
|
|
});
|
|
|
|
group('StraightLineRouteProvider tests', () {
|
|
const provider = StraightLineRouteProvider();
|
|
|
|
test('builds straight-line polyline and calculates distance', () async {
|
|
const stops = [
|
|
RouteStop(
|
|
id: 's1',
|
|
latitude: 37.7749,
|
|
longitude: -122.4194,
|
|
displayName: 'SF',
|
|
stopType: RouteStopType.origin,
|
|
orderIndex: 0,
|
|
),
|
|
RouteStop(
|
|
id: 's2',
|
|
latitude: 37.3382,
|
|
longitude: -121.8863,
|
|
displayName: 'San Jose',
|
|
stopType: RouteStopType.destination,
|
|
orderIndex: 1,
|
|
),
|
|
];
|
|
|
|
final result = await provider.calculateRoute(stops);
|
|
expect(result.points.length, equals(2));
|
|
expect(result.points[0].latitude, equals(37.7749));
|
|
expect(result.points[1].latitude, equals(37.3382));
|
|
expect(result.totalDistanceMeters, greaterThan(65000));
|
|
expect(result.isHonestStraightLine, isTrue);
|
|
});
|
|
|
|
test('empty stops produces zero points and zero distance', () async {
|
|
final result = await provider.calculateRoute(const []);
|
|
expect(result.points.isEmpty, isTrue);
|
|
expect(result.totalDistanceMeters, equals(0.0));
|
|
});
|
|
});
|
|
|
|
group('NavigationHandoffService URI tests', () {
|
|
test('builds valid Google Maps navigation URI', () {
|
|
final uri = NavigationHandoffService.buildGoogleMapsUri(
|
|
latitude: 37.7749,
|
|
longitude: -122.4194,
|
|
displayName: 'San Francisco Hub',
|
|
);
|
|
|
|
expect(uri.scheme, equals('https'));
|
|
expect(uri.host, equals('www.google.com'));
|
|
expect(uri.path, equals('/maps/dir/'));
|
|
expect(uri.queryParameters['api'], equals('1'));
|
|
expect(uri.queryParameters['destination'], equals('37.774900,-122.419400'));
|
|
});
|
|
|
|
test('builds valid Waze navigation URI', () {
|
|
final uri = NavigationHandoffService.buildWazeUri(
|
|
latitude: 37.7749,
|
|
longitude: -122.4194,
|
|
);
|
|
|
|
expect(uri.scheme, equals('https'));
|
|
expect(uri.host, equals('waze.com'));
|
|
expect(uri.path, equals('/ul'));
|
|
expect(uri.queryParameters['ll'], equals('37.774900,-122.419400'));
|
|
expect(uri.queryParameters['navigate'], equals('yes'));
|
|
});
|
|
|
|
test('builds valid system geo URI', () {
|
|
final uri = NavigationHandoffService.buildSystemGeoUri(
|
|
latitude: 37.7749,
|
|
longitude: -122.4194,
|
|
displayName: 'SF Landmark',
|
|
);
|
|
|
|
expect(uri.scheme, equals('geo'));
|
|
expect(uri.path, equals('37.774900,-122.419400'));
|
|
expect(uri.queryParameters['q'], equals('37.774900,-122.419400(SF Landmark)'));
|
|
});
|
|
});
|
|
}
|