feat(app): add evaluation history, bot control panel, simulation visualizer, and vendored signalr_core

This commit is contained in:
2026-08-24 21:37:43 +02:00
parent 676496b77d
commit 0894c40f07
113 changed files with 12413 additions and 3613 deletions
@@ -0,0 +1,80 @@
import 'package:signalr_core/signalr_core.dart';
import 'package:test/test.dart';
void main() {
test(
'withAutomaticReconnect uses default retryDelays when called with no arguments',
() {
// From DefaultReconnectPolicy.dart
final defaultRetryDelaysInMilliseconds = [0, 2000, 10000, 30000, null];
final builder = HubConnectionBuilder().withAutomaticReconnect();
var retryCount = 0;
for (var delay in defaultRetryDelaysInMilliseconds) {
final retryContext = RetryContext(
previousRetryCount: retryCount++,
elapsedMilliseconds: 0,
retryReason: Exception(),
);
expect(builder.reconnectPolicy!.nextRetryDelayInMilliseconds(retryContext),
delay);
}
});
test('withAutomaticReconnect uses custom retryDelays when provided', () {
final customRetryDelays = [3, 1, 4, 1, 5, 9];
final builder =
HubConnectionBuilder().withAutomaticReconnect(customRetryDelays);
var retryCount = 0;
for (var delay in customRetryDelays) {
final retryContext = RetryContext(
previousRetryCount: retryCount++,
elapsedMilliseconds: 0,
retryReason: Exception(),
);
expect(builder.reconnectPolicy!.nextRetryDelayInMilliseconds(retryContext),
delay);
}
// TODO: This test fails in Dart but looks like works using Typescript's testing framework
// final retryContextFinal = RetryContext(
// previousRetryCount: retryCount++,
// elapsedMilliseconds: 0,
// retryReason: Exception());
// expect(
// builder.reconnectPolicy.nextRetryDelayInMilliseconds(retryContextFinal),
// null);
});
test('withAutomaticReconnect uses a custom RetryPolicy when provided', () {
final customRetryDelays = [127, 0, 0, 1];
final builder = HubConnectionBuilder().withAutomaticReconnect(
DefaultReconnectPolicy(retryDelays: customRetryDelays));
var retryCount = 0;
for (var delay in customRetryDelays) {
final retryContext = RetryContext(
previousRetryCount: retryCount++,
elapsedMilliseconds: 0,
retryReason: Exception(),
);
expect(builder.reconnectPolicy!.nextRetryDelayInMilliseconds(retryContext),
delay);
}
// TODO: This test fails in Dart but looks like works using Typescript's testing framework
// final retryContextFinal = RetryContext(
// previousRetryCount: retryCount++,
// elapsedMilliseconds: 0,
// retryReason: Exception());
// expect(
// builder.reconnectPolicy.nextRetryDelayInMilliseconds(retryContextFinal),
// null);
});
}
@@ -0,0 +1,25 @@
import 'package:signalr_core/src/hub_protocol.dart';
import 'package:signalr_core/src/json_hub_protocol.dart';
import 'package:signalr_core/src/text_message_format.dart';
import 'package:test/test.dart';
void main() {
test('can read ping message', () {
final payload = '{"type":6}${TextMessageFormat.recordSeparator}';
final messages = JsonHubProtocol()
.parseMessages(payload, (level, message) => print(message));
expect(messages, equals([PingMessage()]));
});
test('can read completion message', () {
final payload = '{"type":3,"invocationId":"0","result":{"data":"123"}}'
'${TextMessageFormat.recordSeparator}';
final messages = JsonHubProtocol()
.parseMessages(payload, (level, message) => print(message));
expect(
messages,
equals([
CompletionMessage(invocationId: '0', result: {'data': '123'})
]));
});
}
@@ -0,0 +1,35 @@
import 'package:signalr_core/src/text_message_format.dart';
import 'package:test/test.dart';
const Map<String, List<String>> messages = {
'\u001e': [''],
'\u001e\u001e': ['', ''],
'Hello\u001e': ['Hello'],
'Hello,\u001eWorld!\u001e': ['Hello,', 'World!']
};
void main() {
group('TextMessageFormat', () {
Map<String, List<String>>.from({
'\u001e': [''],
'\u001e\u001e': ['', ''],
'Hello\u001e': ['Hello'],
'Hello,\u001eWorld!\u001e': ['Hello,', 'World!']
}).forEach((payload, expectedMessages) {
test('should parse \'${Uri.encodeComponent(payload)}\' correctly', () {
final messages = TextMessageFormat.parse(payload);
expect(messages, expectedMessages);
});
});
Map<String, String>.from({
'': 'Message is incomplete.',
'ABC': 'Message is incomplete.',
'ABC\u001eXYZ': 'Message is incomplete.',
}).forEach((payload, expectedError) {
test('should fail to parse \'${Uri.encodeComponent(payload)}\'', () {
//expect(() => TextMessageFormat.parse(payload), predicate((Exception e) => e is Exception && e.message == 'Message is incomplete.'));
});
});
});
}