| // Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'package:test/test.dart'; |
| import 'package:test_case_selector/test_case_selector.dart'; |
| |
| enum VehicleType { bicycle, motorcycle, car, semiTruck } |
| |
| enum PaintColor { crimsonRed, stealthBlack, arcticWhite } |
| |
| enum WeightClass { ultraLight, light, medium, heavy } |
| |
| enum TestDimA { a1, a2 } |
| |
| enum TestDimB { b1, b2 } |
| |
| enum TestDimC { c1, c2 } |
| |
| void main() { |
| group('TestCaseSelector (Vehicle Configurator)', () { |
| test('covers all colors and vehicle types', () { |
| final vehicles = VehicleType.values; |
| final colors = PaintColor.values; |
| |
| final configurations = |
| TestCaseSelector( |
| dimensions: { |
| VehicleType: vehicles, |
| PaintColor: colors, |
| }, |
| interactionGroups: [ |
| {VehicleType, PaintColor}, |
| ], |
| ).select(); |
| |
| // Verify all individual values are covered. |
| for (final v in vehicles) { |
| expect(configurations.any((tc) => tc.get<VehicleType>() == v), isTrue); |
| } |
| for (final c in colors) { |
| expect(configurations.any((tc) => tc.get<PaintColor>() == c), isTrue); |
| } |
| |
| // Verify all interaction pairs (Cartesian product since it's one group). |
| for (final v in vehicles) { |
| for (final c in colors) { |
| expect( |
| configurations.any( |
| (tc) => tc.get<VehicleType>() == v && tc.get<PaintColor>() == c, |
| ), |
| isTrue, |
| ); |
| } |
| } |
| |
| expect(configurations.length, 12); // 4 types * 3 colors |
| }); |
| |
| test('reduces configurations with multiple interaction groups', () { |
| final configurations = |
| TestCaseSelector( |
| dimensions: { |
| VehicleType: VehicleType.values, |
| PaintColor: PaintColor.values, |
| WeightClass: WeightClass.values, |
| }, |
| interactionGroups: [ |
| {VehicleType, WeightClass}, |
| {VehicleType, PaintColor}, |
| ], |
| ).select(); |
| |
| // Verify interaction pairs from both groups are covered. |
| for (final v in VehicleType.values) { |
| for (final w in WeightClass.values) { |
| expect( |
| configurations.any( |
| (c) => c.get<VehicleType>() == v && c.get<WeightClass>() == w, |
| ), |
| isTrue, |
| ); |
| } |
| for (final p in PaintColor.values) { |
| expect( |
| configurations.any( |
| (c) => c.get<VehicleType>() == v && c.get<PaintColor>() == p, |
| ), |
| isTrue, |
| ); |
| } |
| } |
| |
| // Full product: 4 * 3 * 4 = 48. |
| // Pairwise should be much lower (around 16). |
| expect(configurations.length, lessThan(30)); |
| expect(configurations.length, greaterThanOrEqualTo(16)); |
| }); |
| |
| test('covers full cross-product for 3-way interaction group', () { |
| final configurations = |
| TestCaseSelector( |
| dimensions: { |
| TestDimA: TestDimA.values, |
| TestDimB: TestDimB.values, |
| TestDimC: TestDimC.values, |
| }, |
| interactionGroups: [ |
| {TestDimA, TestDimB, TestDimC}, |
| ], |
| ).select(); |
| |
| final seen = <String>{}; |
| for (final tc in configurations) { |
| seen.add( |
| '${tc.get<TestDimA>()},${tc.get<TestDimB>()},${tc.get<TestDimC>()}', |
| ); |
| } |
| |
| for (final a in TestDimA.values) { |
| for (final b in TestDimB.values) { |
| for (final c in TestDimC.values) { |
| expect( |
| seen.contains('$a,$b,$c'), |
| isTrue, |
| reason: 'Combination $a,$b,$c should be covered', |
| ); |
| } |
| } |
| } |
| |
| expect(configurations.length, 8); // 2 * 2 * 2 |
| }); |
| |
| test('respects vehicle weight constraints (isValid)', () { |
| final configurations = |
| TestCaseSelector( |
| dimensions: { |
| VehicleType: VehicleType.values, |
| WeightClass: WeightClass.values, |
| }, |
| interactionGroups: [ |
| {VehicleType, WeightClass}, |
| ], |
| isValid: (tc) { |
| final type = tc.get<VehicleType>(); |
| final weight = tc.get<WeightClass>(); |
| |
| if (type == VehicleType.bicycle) { |
| return weight == WeightClass.ultraLight; |
| } |
| if (type == VehicleType.semiTruck) { |
| return weight == WeightClass.heavy; |
| } |
| if (type == VehicleType.motorcycle) { |
| return weight != WeightClass.heavy; |
| } |
| return true; |
| }, |
| ).select(); |
| |
| for (final tc in configurations) { |
| final type = tc.get<VehicleType>(); |
| final weight = tc.get<WeightClass>(); |
| |
| if (type == VehicleType.bicycle) { |
| expect(weight, WeightClass.ultraLight); |
| } else if (type == VehicleType.semiTruck) { |
| expect(weight, WeightClass.heavy); |
| } else if (type == VehicleType.motorcycle) { |
| expect(weight, isNot(WeightClass.heavy)); |
| } |
| } |
| }); |
| }); |
| } |