feat: add TestRunViewModel with state management
This commit is contained in:
@@ -0,0 +1,58 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:iperf3gui/data/services/iperf3_service.dart';
|
||||||
|
import 'package:iperf3gui/domain/models/test_configuration.dart';
|
||||||
|
import 'package:iperf3gui/domain/models/iperf3_result.dart';
|
||||||
|
|
||||||
|
/// State of the test run.
|
||||||
|
enum TestRunState { idle, running, completed, error }
|
||||||
|
|
||||||
|
/// ViewModel for managing test run state.
|
||||||
|
class TestRunViewModel extends ChangeNotifier {
|
||||||
|
final Iperf3Service _iperf3Service;
|
||||||
|
|
||||||
|
TestRunState _state = TestRunState.idle;
|
||||||
|
TestRunState get state => _state;
|
||||||
|
|
||||||
|
Iperf3Result? _result;
|
||||||
|
Iperf3Result? get result => _result;
|
||||||
|
|
||||||
|
TestConfiguration? _currentConfig;
|
||||||
|
TestConfiguration? get currentConfig => _currentConfig;
|
||||||
|
|
||||||
|
TestRunViewModel({required Iperf3Service iperf3Service})
|
||||||
|
: _iperf3Service = iperf3Service;
|
||||||
|
|
||||||
|
/// Start a test with the given configuration.
|
||||||
|
Future<void> runTest(TestConfiguration config) async {
|
||||||
|
if (!config.isValid) {
|
||||||
|
_state = TestRunState.error;
|
||||||
|
notifyListeners();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_state = TestRunState.running;
|
||||||
|
_currentConfig = config;
|
||||||
|
_result = null;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final result = await _iperf3Service.run(config);
|
||||||
|
_result = result;
|
||||||
|
_state = result.exitCode == 0
|
||||||
|
? TestRunState.completed
|
||||||
|
: TestRunState.error;
|
||||||
|
} catch (e) {
|
||||||
|
_state = TestRunState.error;
|
||||||
|
} finally {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset to idle state.
|
||||||
|
void reset() {
|
||||||
|
_state = TestRunState.idle;
|
||||||
|
_result = null;
|
||||||
|
_currentConfig = null;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:iperf3gui/data/services/iperf3_service.dart';
|
||||||
|
import 'package:iperf3gui/domain/models/iperf3_result.dart';
|
||||||
|
import 'package:iperf3gui/domain/models/test_configuration.dart';
|
||||||
|
import 'package:iperf3gui/ui/features/test_run/test_run_view_model.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('TestRunViewModel', () {
|
||||||
|
test('starts in idle state', () {
|
||||||
|
final vm = TestRunViewModel(
|
||||||
|
iperf3Service: _MockIperf3Service(),
|
||||||
|
);
|
||||||
|
expect(vm.state, equals(TestRunState.idle));
|
||||||
|
expect(vm.result, isNull);
|
||||||
|
expect(vm.currentConfig, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('can be reset', () {
|
||||||
|
final vm = TestRunViewModel(
|
||||||
|
iperf3Service: _MockIperf3Service(),
|
||||||
|
);
|
||||||
|
vm.reset();
|
||||||
|
expect(vm.state, equals(TestRunState.idle));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('invalid config sets error state without running', () async {
|
||||||
|
final vm = TestRunViewModel(
|
||||||
|
iperf3Service: _MockIperf3Service(),
|
||||||
|
);
|
||||||
|
const config = TestConfiguration(server: '');
|
||||||
|
await vm.runTest(config);
|
||||||
|
expect(vm.state, equals(TestRunState.error));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('runTest with valid config calls service', () async {
|
||||||
|
final mock = _MockIperf3Service(
|
||||||
|
onRun: (config) async {
|
||||||
|
expect(config.server, equals('192.168.1.1'));
|
||||||
|
return Iperf3Result(rawOutput: 'done', exitCode: 0);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final vm = TestRunViewModel(iperf3Service: mock);
|
||||||
|
const config = TestConfiguration(server: '192.168.1.1');
|
||||||
|
await vm.runTest(config);
|
||||||
|
expect(vm.state, equals(TestRunState.completed));
|
||||||
|
expect(vm.result, isNotNull);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MockIperf3Service implements Iperf3Service {
|
||||||
|
_MockIperf3Service({this.onRun});
|
||||||
|
|
||||||
|
final Future<Iperf3Result> Function(TestConfiguration)? onRun;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Iperf3Result> run(TestConfiguration config) async {
|
||||||
|
if (onRun != null) return onRun!(config);
|
||||||
|
return Iperf3Result(rawOutput: '', exitCode: 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user