feat(ground-suite): add local vehicle catalog
This commit is contained in:
1 parent
2fe54fb053
commit
cc9e9919db
18 files changed
+778
-6
No files matched your search
@@ -0,0 +1,77 @@
|
||||
import 'dart:ui' show CheckedState;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:ground_suite/features/vehicle_workspace/domain/vehicle_catalog.dart';
|
||||
import 'package:ground_suite/features/vehicle_workspace/presentation/widgets/vehicle_catalog_card.dart';
|
||||
|
||||
void main() {
|
||||
test('every local vehicle type has a clear bundled profile image', () {
|
||||
expect(supportedVehicleDefinitions, hasLength(6));
|
||||
expect(
|
||||
supportedVehicleDefinitions.map((definition) => definition.name),
|
||||
containsAll(<String>[
|
||||
'Quadcopter',
|
||||
'Fixed-wing',
|
||||
'Tiltrotor VTOL',
|
||||
'Helicopter',
|
||||
'Ground rover',
|
||||
'Surface vessel',
|
||||
]),
|
||||
);
|
||||
for (final definition in supportedVehicleDefinitions) {
|
||||
expect(definition.id, isNotEmpty);
|
||||
expect(definition.name, isNotEmpty);
|
||||
expect(definition.media.imageAssetPath, isNotEmpty);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('catalog card is a single keyboard-activatable radio control', (
|
||||
tester,
|
||||
) async {
|
||||
var selections = 0;
|
||||
final definition = supportedVehicleDefinitions.first;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 760,
|
||||
child: VehicleCatalogCard(
|
||||
definition: definition,
|
||||
selected: false,
|
||||
onSelected: () => selections += 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final card = find.byType(VehicleCatalogCard);
|
||||
final semantics = tester.getSemantics(card);
|
||||
expect(semantics.flagsCollection.isChecked, CheckedState.isFalse);
|
||||
expect(semantics.flagsCollection.isInMutuallyExclusiveGroup, isTrue);
|
||||
expect(semantics.label, contains('local vehicle image, not telemetry'));
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
|
||||
await tester.pump();
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.space);
|
||||
await tester.pump();
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
|
||||
await tester.pump();
|
||||
|
||||
expect(selections, 2);
|
||||
});
|
||||
|
||||
testWidgets('definition images are bundled locally', (tester) async {
|
||||
for (final definition in supportedVehicleDefinitions) {
|
||||
final image = await rootBundle.load(definition.media.imageAssetPath);
|
||||
expect(image.lengthInBytes, greaterThan(0));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:ground_suite/features/fleet/domain/fleet_unit.dart';
|
||||
import 'package:ground_suite/features/vehicle_workspace/domain/vehicle_catalog.dart';
|
||||
import 'package:ground_suite/features/vehicle_workspace/presentation/vehicle_workspace_controller.dart';
|
||||
|
||||
void main() {
|
||||
test('a reviewed definition creates a selected local fleet unit', () {
|
||||
final container = ProviderContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
final controller = container.read(vehicleWorkspaceProvider.notifier);
|
||||
expect(container.read(vehicleWorkspaceProvider).hasUnits, isFalse);
|
||||
|
||||
final definition = supportedVehicleDefinitions.first;
|
||||
expect(
|
||||
controller.addUnit(
|
||||
definition: definition,
|
||||
localPlacement: const LocalScenePoint(x: .35, y: .45),
|
||||
displayName: 'North survey',
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
expect(container.read(vehicleWorkspaceProvider).hasUnits, isTrue);
|
||||
expect(
|
||||
container.read(vehicleWorkspaceProvider).units.single.definition,
|
||||
definition,
|
||||
);
|
||||
expect(
|
||||
container.read(vehicleWorkspaceProvider).units.single.localUnitId,
|
||||
'local-unit-1',
|
||||
);
|
||||
expect(
|
||||
container.read(vehicleWorkspaceProvider).units.single.displayName,
|
||||
'North survey',
|
||||
);
|
||||
|
||||
expect(
|
||||
controller.addUnit(
|
||||
definition: definition,
|
||||
localPlacement: const LocalScenePoint(x: .72, y: .45),
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
expect(container.read(vehicleWorkspaceProvider).units, hasLength(2));
|
||||
expect(
|
||||
container.read(vehicleWorkspaceProvider).units.last.localUnitId,
|
||||
'local-unit-2',
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'rejects overlapping local placements and keeps a bounded workspace',
|
||||
() {
|
||||
final container = ProviderContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
final controller = container.read(vehicleWorkspaceProvider.notifier);
|
||||
final definition = supportedVehicleDefinitions.first;
|
||||
const first = LocalScenePoint(x: .2, y: .2);
|
||||
expect(
|
||||
controller.addUnit(definition: definition, localPlacement: first),
|
||||
isTrue,
|
||||
);
|
||||
expect(
|
||||
controller.addUnit(definition: definition, localPlacement: first),
|
||||
isFalse,
|
||||
);
|
||||
|
||||
expect(
|
||||
controller.addUnit(
|
||||
definition: definition,
|
||||
localPlacement: const LocalScenePoint(x: .23, y: .2),
|
||||
),
|
||||
isFalse,
|
||||
);
|
||||
expect(
|
||||
controller.addUnit(
|
||||
definition: definition,
|
||||
localPlacement: const LocalScenePoint(x: .65, y: .7),
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'catalog additions receive a scattered local presentation placement',
|
||||
() {
|
||||
final container = ProviderContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
final controller = container.read(vehicleWorkspaceProvider.notifier);
|
||||
final definition = supportedVehicleDefinitions.first;
|
||||
expect(controller.addUnitAutomatically(definition: definition), isTrue);
|
||||
expect(controller.addUnitAutomatically(definition: definition), isTrue);
|
||||
|
||||
final units = container.read(vehicleWorkspaceProvider).units;
|
||||
expect(units, hasLength(2));
|
||||
expect(units.first.localPlacement, isNot(units.last.localPlacement));
|
||||
for (final unit in units) {
|
||||
expect(unit.localPlacement.x, inInclusiveRange(0.0, 1.0));
|
||||
expect(unit.localPlacement.y, inInclusiveRange(0.0, 1.0));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'local unit names are bounded workspace data, not vehicle configuration',
|
||||
() {
|
||||
final container = ProviderContainer();
|
||||
addTearDown(container.dispose);
|
||||
|
||||
final controller = container.read(vehicleWorkspaceProvider.notifier);
|
||||
expect(
|
||||
controller.addUnitAutomatically(
|
||||
definition: supportedVehicleDefinitions.first,
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
expect(
|
||||
controller.renameUnit('local-unit-1', ' Ridge observer '),
|
||||
isTrue,
|
||||
);
|
||||
expect(
|
||||
container.read(vehicleWorkspaceProvider).units.single.displayName,
|
||||
'Ridge observer',
|
||||
);
|
||||
expect(controller.renameUnit('local-unit-1', ' '), isFalse);
|
||||
expect(
|
||||
container.read(vehicleWorkspaceProvider).units.single.displayName,
|
||||
'Ridge observer',
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user