743 lines
28 KiB
Dart
743 lines
28 KiB
Dart
// Here's the plan:
|
|
// This class will take an instance of ModList and manipulate it in various ways
|
|
// What we want to achieve is two things:
|
|
// A) a binary search / bisect algorithm to find the minimum set of mods
|
|
// that exhibit a bug
|
|
// B) a linear search / batching algorithm for the same purpose
|
|
// Why both? I think B will be most useful most often but A theoretically
|
|
// should be faster
|
|
// Why I think A might not always be faster is because it takes us a very long
|
|
// time to load a lot of mods
|
|
// So say it takes us 30 minutes to load 300 mods
|
|
// Via bisect we would be loading 30 + 15 + 7.5 + ... = some 50 minutes
|
|
// Via linear search we would be loading say 30 mods at a time
|
|
// Which would be 3 minutes per batch for 10 batches
|
|
// ie. 30 minutes
|
|
// Reality is a little bit more complicated than that but that is the theory
|
|
|
|
// Now - how should this class do what I detailed it to do
|
|
// Keep the original ModList and copy it for every iteration
|
|
// Whether that be an iteration of bisect or a batch of linear search
|
|
// For every new batch make sure all its dependencies are loaded (ModList.loadRequired())
|
|
// Then try run game and proceed to next batch (or don't)
|
|
// Progressively our ModList will shrink (or not, regardless)
|
|
// And we should keep a registry of tested (say Good) mods and ones we haven't gotten to yet
|
|
// Maybe even make sure each batch contains N untested mods
|
|
// And that we don't test the same mod twice (unless it's a library)
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:rimworld_modman/mod.dart';
|
|
import 'package:rimworld_modman/mod_list.dart';
|
|
import 'package:rimworld_modman/mod_list_troubleshooter.dart';
|
|
|
|
Mod makeDummy() {
|
|
return Mod(
|
|
name: 'Dummy Mod',
|
|
id: 'dummy',
|
|
path: '',
|
|
versions: ["1.5"],
|
|
description: '',
|
|
dependencies: [],
|
|
loadAfter: [],
|
|
loadBefore: [],
|
|
incompatibilities: [],
|
|
size: 0,
|
|
isBaseGame: false,
|
|
isExpansion: false,
|
|
enabled: false,
|
|
);
|
|
}
|
|
|
|
void main() {
|
|
group('Bisect Tests', () {
|
|
late ModList modList = ModList();
|
|
setUp(() {
|
|
modList = ModList();
|
|
|
|
// Add some base mods
|
|
for (int i = 0; i < 20; i++) {
|
|
final modId = 'test.mod$i';
|
|
final mod = makeDummy().copyWith(name: 'Test Mod $i', id: modId);
|
|
modList.mods[modId] = mod;
|
|
}
|
|
|
|
// Add some mods with dependencies
|
|
for (int i = 20; i < 30; i++) {
|
|
final modId = 'test.mod$i';
|
|
final mod = makeDummy().copyWith(
|
|
name: 'Test Mod $i',
|
|
id: modId,
|
|
dependencies: ['test.mod${i - 20}'], // Depend on earlier mods
|
|
);
|
|
modList.mods[modId] = mod;
|
|
}
|
|
modList.enableAll();
|
|
});
|
|
|
|
test(
|
|
'Should end up with half the mods every forward iteration until 1',
|
|
() {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.binaryForward();
|
|
// Half of our initial 30
|
|
expect(result.activeMods.length, equals(15));
|
|
expect(result.activeMods.keys.first, equals('test.mod15'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
// Half of our previous result
|
|
expect(result.activeMods.length, equals(8));
|
|
expect(result.activeMods.keys.first, equals('test.mod22'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(4));
|
|
expect(result.activeMods.keys.first, equals('test.mod26'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(2));
|
|
expect(result.activeMods.keys.first, equals('test.mod28'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(1));
|
|
expect(result.activeMods.keys.first, equals('test.mod29'));
|
|
},
|
|
);
|
|
test(
|
|
'Should end up with half the mods every backward iteration until 1',
|
|
() {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.binaryBackward();
|
|
// Half of our initial 30
|
|
expect(result.activeMods.length, equals(15));
|
|
expect(result.activeMods.keys.last, equals('test.mod14'));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
// Half of our previous result
|
|
expect(result.activeMods.length, equals(8));
|
|
expect(result.activeMods.keys.last, equals('test.mod7'));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(4));
|
|
expect(result.activeMods.keys.last, equals('test.mod3'));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(2));
|
|
expect(result.activeMods.keys.last, equals('test.mod1'));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(1));
|
|
expect(result.activeMods.keys.last, equals('test.mod0'));
|
|
},
|
|
);
|
|
test('Should end up with half the mods every iteration until 1', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.binaryBackward();
|
|
// Half of our initial 30
|
|
expect(result.activeMods.length, equals(15));
|
|
expect(result.activeMods.keys.last, equals('test.mod14'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
// Half of our previous result
|
|
expect(result.activeMods.length, equals(8));
|
|
expect(result.activeMods.keys.first, equals('test.mod7'));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(4));
|
|
expect(result.activeMods.keys.last, equals('test.mod10'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(2));
|
|
expect(result.activeMods.keys.first, equals('test.mod9'));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(1));
|
|
expect(result.activeMods.keys.last, equals('test.mod9'));
|
|
});
|
|
test('Should handle abuse gracefully', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(15));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(8));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(4));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(2));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(1));
|
|
expect(result.activeMods.keys.first, equals('test.mod9'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(1));
|
|
expect(result.activeMods.keys.first, equals('test.mod9'));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(1));
|
|
expect(result.activeMods.keys.first, equals('test.mod9'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(1));
|
|
expect(result.activeMods.keys.first, equals('test.mod9'));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(1));
|
|
expect(result.activeMods.keys.first, equals('test.mod9'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(1));
|
|
expect(result.activeMods.keys.first, equals('test.mod9'));
|
|
});
|
|
});
|
|
|
|
group('Linear Tests', () {
|
|
late ModList modList = ModList();
|
|
setUp(() {
|
|
modList = ModList();
|
|
|
|
// Add some base mods
|
|
for (int i = 0; i < 20; i++) {
|
|
final modId = 'test.mod$i';
|
|
final mod = makeDummy().copyWith(name: 'Test Mod $i', id: modId);
|
|
modList.mods[modId] = mod;
|
|
}
|
|
|
|
// Add some mods with dependencies
|
|
for (int i = 20; i < 30; i++) {
|
|
final modId = 'test.mod$i';
|
|
final mod = makeDummy().copyWith(
|
|
name: 'Test Mod $i',
|
|
id: modId,
|
|
dependencies: ['test.mod${i - 20}'], // Depend on earlier mods
|
|
);
|
|
modList.mods[modId] = mod;
|
|
}
|
|
modList.enableAll();
|
|
});
|
|
|
|
test('Should end up with 10 mods every forward iteration', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod9'));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod10'));
|
|
expect(result.activeMods.keys.last, equals('test.mod19'));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod20'));
|
|
expect(result.activeMods.keys.last, equals('test.mod29'));
|
|
});
|
|
test('Should end up with 10 mods every backward iteration', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod20'));
|
|
expect(result.activeMods.keys.last, equals('test.mod29'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod10'));
|
|
expect(result.activeMods.keys.last, equals('test.mod19'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod9'));
|
|
});
|
|
test('Should end up with 10 mods every iteration', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod20'));
|
|
expect(result.activeMods.keys.last, equals('test.mod29'));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod20'));
|
|
expect(result.activeMods.keys.last, equals('test.mod29'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod10'));
|
|
expect(result.activeMods.keys.last, equals('test.mod19'));
|
|
});
|
|
test('Should handle abuse gracefully', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
});
|
|
test('Should handle different step sizes', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
});
|
|
test('Cannot return more items than there are', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.linearBackward(stepSize: 10000);
|
|
expect(result.activeMods.length, equals(30));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10000);
|
|
expect(result.activeMods.length, equals(30));
|
|
});
|
|
});
|
|
group('Navigation tests', () {
|
|
late ModList modList = ModList();
|
|
setUp(() {
|
|
modList = ModList();
|
|
|
|
// Add some base mods
|
|
for (int i = 0; i < 20; i++) {
|
|
final modId = 'test.mod$i';
|
|
final mod = makeDummy().copyWith(name: 'Test Mod $i', id: modId);
|
|
modList.mods[modId] = mod;
|
|
}
|
|
|
|
// Add some mods with dependencies
|
|
for (int i = 20; i < 30; i++) {
|
|
final modId = 'test.mod$i';
|
|
final mod = makeDummy().copyWith(
|
|
name: 'Test Mod $i',
|
|
id: modId,
|
|
dependencies: ['test.mod${i - 20}'], // Depend on earlier mods
|
|
);
|
|
modList.mods[modId] = mod;
|
|
}
|
|
modList.enableAll();
|
|
});
|
|
|
|
test('Mixed navigation should work', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod9'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(5));
|
|
expect(result.activeMods.keys.first, equals('test.mod5'));
|
|
expect(result.activeMods.keys.last, equals('test.mod9'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod9'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(5));
|
|
expect(result.activeMods.keys.first, equals('test.mod5'));
|
|
expect(result.activeMods.keys.last, equals('test.mod9'));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod5'));
|
|
expect(result.activeMods.keys.last, equals('test.mod14'));
|
|
});
|
|
|
|
test('Complex navigation sequence should work correctly', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(15));
|
|
expect(result.activeMods.keys.first, equals('test.mod15'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 5);
|
|
expect(result.activeMods.length, equals(5));
|
|
expect(result.activeMods.keys.first, equals('test.mod25'));
|
|
expect(result.activeMods.keys.last, equals('test.mod29'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(3));
|
|
expect(result.activeMods.keys.first, equals('test.mod27'));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 2);
|
|
expect(result.activeMods.length, equals(2));
|
|
expect(result.activeMods.keys.first, equals('test.mod27'));
|
|
expect(result.activeMods.keys.last, equals('test.mod28'));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(1));
|
|
expect(result.activeMods.keys.first, equals('test.mod27'));
|
|
});
|
|
|
|
test('Varying step sizes in linear navigation', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.linearForward(stepSize: 15);
|
|
expect(result.activeMods.length, equals(15));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod14'));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 5);
|
|
expect(result.activeMods.length, equals(5));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod4'));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 2);
|
|
expect(result.activeMods.length, equals(2));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod1'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 3);
|
|
expect(result.activeMods.length, equals(3));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod2'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 7);
|
|
expect(result.activeMods.length, equals(7));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod6'));
|
|
});
|
|
|
|
test('Edge case - switching approaches at the boundary', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod20'));
|
|
expect(result.activeMods.keys.last, equals('test.mod29'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod10'));
|
|
expect(result.activeMods.keys.last, equals('test.mod19'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod9'));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(5));
|
|
expect(result.activeMods.keys.first, equals('test.mod5'));
|
|
expect(result.activeMods.keys.last, equals('test.mod9'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 2);
|
|
expect(result.activeMods.length, equals(2));
|
|
expect(result.activeMods.keys.first, equals('test.mod8'));
|
|
expect(result.activeMods.keys.last, equals('test.mod9'));
|
|
});
|
|
|
|
test('Testing reset/restart behavior', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
// Do some navigation first
|
|
var result = troubleshooter.linearForward(stepSize: 5);
|
|
expect(result.activeMods.length, equals(5));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(3));
|
|
|
|
// Create a new troubleshooter with the same mod list (simulating reset)
|
|
final newTroubleshooter = ModListTroubleshooter(modList);
|
|
|
|
// First operation should work as if we're starting fresh
|
|
result = newTroubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(15));
|
|
expect(result.activeMods.keys.first, equals('test.mod15'));
|
|
|
|
// Original troubleshooter should still be in its own state
|
|
result = troubleshooter.linearForward(stepSize: 1);
|
|
expect(result.activeMods.length, equals(1));
|
|
});
|
|
|
|
test('Alternate between multiple approaches repeatedly', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
// Alternate between binary and linear several times
|
|
var result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(15));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 5);
|
|
expect(result.activeMods.length, equals(5));
|
|
|
|
result = troubleshooter.binaryForward();
|
|
expect(result.activeMods.length, equals(3));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 1);
|
|
expect(result.activeMods.length, equals(1));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
|
|
result = troubleshooter.binaryBackward();
|
|
expect(result.activeMods.length, equals(5));
|
|
|
|
// Final set of mods should be consistent with the operations performed
|
|
expect(result.activeMods.length, equals(5));
|
|
});
|
|
|
|
// These tests specifically examine the nuances of linear navigation
|
|
test('Linear navigation window adjustment - forward', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
// First linearForward with a specific step size
|
|
var result = troubleshooter.linearForward(stepSize: 8);
|
|
expect(result.activeMods.length, equals(8));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod7'));
|
|
|
|
// Second call should move forward since current selection size matches step size
|
|
result = troubleshooter.linearForward(stepSize: 8);
|
|
expect(result.activeMods.length, equals(8));
|
|
expect(result.activeMods.keys.first, equals('test.mod8'));
|
|
expect(result.activeMods.keys.last, equals('test.mod15'));
|
|
|
|
// Change step size - should adapt the window size without moving position
|
|
result = troubleshooter.linearForward(stepSize: 5);
|
|
expect(result.activeMods.length, equals(5));
|
|
expect(result.activeMods.keys.first, equals('test.mod8'));
|
|
expect(result.activeMods.keys.last, equals('test.mod12'));
|
|
|
|
// Move forward with new step size
|
|
result = troubleshooter.linearForward(stepSize: 5);
|
|
expect(result.activeMods.length, equals(5));
|
|
expect(result.activeMods.keys.first, equals('test.mod13'));
|
|
expect(result.activeMods.keys.last, equals('test.mod17'));
|
|
});
|
|
|
|
test('Linear navigation window adjustment - backward', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
// Move to the end first
|
|
troubleshooter.linearBackward(stepSize: 30);
|
|
|
|
// First linearBackward with a specific step size
|
|
var result = troubleshooter.linearBackward(stepSize: 8);
|
|
expect(result.activeMods.length, equals(8));
|
|
expect(result.activeMods.keys.first, equals('test.mod22'));
|
|
expect(result.activeMods.keys.last, equals('test.mod29'));
|
|
|
|
// Second call should move backward since current selection size matches step size
|
|
result = troubleshooter.linearBackward(stepSize: 8);
|
|
expect(result.activeMods.length, equals(8));
|
|
expect(result.activeMods.keys.first, equals('test.mod14'));
|
|
expect(result.activeMods.keys.last, equals('test.mod21'));
|
|
|
|
// Change step size - should adapt the window size without moving position
|
|
result = troubleshooter.linearBackward(stepSize: 5);
|
|
expect(result.activeMods.length, equals(5));
|
|
expect(result.activeMods.keys.first, equals('test.mod17'));
|
|
expect(result.activeMods.keys.last, equals('test.mod21'));
|
|
|
|
// Move backward with new step size
|
|
result = troubleshooter.linearBackward(stepSize: 5);
|
|
expect(result.activeMods.length, equals(5));
|
|
expect(result.activeMods.keys.first, equals('test.mod12'));
|
|
expect(result.activeMods.keys.last, equals('test.mod16'));
|
|
});
|
|
|
|
test('Linear navigation boundary handling - forward', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
var result = troubleshooter.linearForward(stepSize: 25);
|
|
expect(result.activeMods.length, equals(25));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod9'));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod10'));
|
|
expect(result.activeMods.keys.last, equals('test.mod19'));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 3);
|
|
expect(result.activeMods.length, equals(3));
|
|
expect(result.activeMods.keys.first, equals('test.mod10'));
|
|
expect(result.activeMods.keys.last, equals('test.mod12'));
|
|
});
|
|
|
|
test('Linear navigation boundary handling - backward', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
troubleshooter.linearForward(stepSize: 30);
|
|
|
|
var result = troubleshooter.linearBackward(stepSize: 25);
|
|
expect(result.activeMods.length, equals(25));
|
|
expect(result.activeMods.keys.first, equals('test.mod5'));
|
|
expect(result.activeMods.keys.last, equals('test.mod29'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod20'));
|
|
expect(result.activeMods.keys.last, equals('test.mod29'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 10);
|
|
expect(result.activeMods.length, equals(10));
|
|
expect(result.activeMods.keys.first, equals('test.mod10'));
|
|
expect(result.activeMods.keys.last, equals('test.mod19'));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 3);
|
|
expect(result.activeMods.length, equals(3));
|
|
expect(result.activeMods.keys.first, equals('test.mod17'));
|
|
expect(result.activeMods.keys.last, equals('test.mod19'));
|
|
});
|
|
|
|
// Test to verify we always get the requested number of mods at boundaries
|
|
test(
|
|
'Linear navigation always returns exactly stepSize mods when possible',
|
|
() {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
troubleshooter.linearForward(stepSize: 23);
|
|
var result = troubleshooter.linearForward(stepSize: 7);
|
|
expect(result.activeMods.length, equals(7));
|
|
|
|
result = troubleshooter.linearForward(stepSize: 7);
|
|
expect(result.activeMods.length, equals(7));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 23);
|
|
expect(result.activeMods.length, equals(23));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 8);
|
|
expect(result.activeMods.length, equals(8));
|
|
|
|
result = troubleshooter.linearBackward(stepSize: 8);
|
|
expect(result.activeMods.length, equals(8));
|
|
},
|
|
);
|
|
|
|
test('Linear navigation with oversized steps', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
|
|
// Step size larger than total mods
|
|
var result = troubleshooter.linearForward(stepSize: 50);
|
|
expect(result.activeMods.length, equals(30)); // All 30 mods
|
|
expect(result.activeMods.keys.first, equals('test.mod0'));
|
|
expect(result.activeMods.keys.last, equals('test.mod29'));
|
|
|
|
// Forward with oversized step should still return all mods
|
|
result = troubleshooter.linearForward(stepSize: 50);
|
|
expect(result.activeMods.length, equals(30)); // Still all 30 mods
|
|
|
|
// Now with backward
|
|
result = troubleshooter.linearBackward(stepSize: 50);
|
|
expect(result.activeMods.length, equals(30)); // All 30 mods
|
|
|
|
// Another backward with oversized step
|
|
result = troubleshooter.linearBackward(stepSize: 50);
|
|
expect(result.activeMods.length, equals(30)); // Still all 30 mods
|
|
});
|
|
});
|
|
|
|
group('Loading dependencies', () {
|
|
late ModList modList = ModList();
|
|
setUp(() {
|
|
modList = ModList();
|
|
|
|
for (int i = 0; i < 20; i++) {
|
|
final modId = 'test.mod$i';
|
|
var mod = makeDummy().copyWith(name: 'Test Mod $i', id: modId);
|
|
if (i % 3 == 0) {
|
|
mod = mod.copyWith(dependencies: ['test.mod${i + 1}']);
|
|
}
|
|
modList.mods[modId] = mod;
|
|
}
|
|
// Dependencies are:
|
|
// 0 -> 1
|
|
// 3 -> 4
|
|
// 6 -> 7
|
|
// 9 -> 10
|
|
// 12 -> 13
|
|
// 15 -> 16
|
|
// 18 -> 19
|
|
modList.enableAll();
|
|
});
|
|
// Not that it has any reason to since they're completely detached...
|
|
test('Should not fuck up troubleshooter', () {
|
|
final troubleshooter = ModListTroubleshooter(modList);
|
|
final expectedFirst = [
|
|
'test.mod1',
|
|
// 0 depends on 1
|
|
'test.mod0',
|
|
'test.mod2',
|
|
// 3 depends on 4
|
|
'test.mod4',
|
|
'test.mod3',
|
|
'test.mod5',
|
|
// 6 depends on 7
|
|
'test.mod7',
|
|
'test.mod6',
|
|
'test.mod8',
|
|
// 9 depends on 10
|
|
'test.mod10',
|
|
'test.mod9',
|
|
];
|
|
|
|
var result = troubleshooter.linearForward(stepSize: 10);
|
|
var loadOrder = result.loadRequired();
|
|
expect(loadOrder.length, equals(11));
|
|
for (int i = 0; i < expectedFirst.length; i++) {
|
|
expect(loadOrder[i], equals(expectedFirst[i]));
|
|
}
|
|
|
|
final expectedSecond = [
|
|
'test.mod10',
|
|
'test.mod11',
|
|
// 12 depends on 13
|
|
'test.mod13',
|
|
'test.mod12',
|
|
'test.mod14',
|
|
// 15 depends on 16
|
|
'test.mod16',
|
|
'test.mod15',
|
|
'test.mod17',
|
|
// 18 depends on 19
|
|
'test.mod19',
|
|
'test.mod18',
|
|
];
|
|
|
|
result = troubleshooter.linearForward(stepSize: 10);
|
|
loadOrder = result.loadRequired();
|
|
expect(loadOrder.length, equals(10));
|
|
for (int i = 0; i < expectedSecond.length; i++) {
|
|
expect(loadOrder[i], equals(expectedSecond[i]));
|
|
}
|
|
});
|
|
});
|
|
}
|