Initial flame_lua_runtime package
This commit is contained in:
170
test/runtime/events/runtime_event_dispatcher_test.dart
Normal file
170
test/runtime/events/runtime_event_dispatcher_test.dart
Normal file
@@ -0,0 +1,170 @@
|
||||
import 'package:flame_lua_runtime/runtime/diagnostics/runtime_diagnostics.dart';
|
||||
import 'package:flame_lua_runtime/runtime/events/runtime_event_dispatcher.dart';
|
||||
import 'package:flame_lua_runtime/runtime/lifecycle/runtime_session.dart';
|
||||
import 'package:flame_lua_runtime/runtime/models/game_diff.dart';
|
||||
import 'package:flame_lua_runtime/runtime/models/runtime_event.dart';
|
||||
import 'package:flame_lua_runtime/runtime/packages/game_package.dart';
|
||||
import 'package:flame_lua_runtime/runtime/scripting/script_engine.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('RuntimeEventDispatcher', () {
|
||||
test('dispatches queued events serially', () async {
|
||||
final session = _activeSession();
|
||||
final script = _FakeScriptEngine();
|
||||
final applied = <GameDiff>[];
|
||||
final dispatcher = RuntimeEventDispatcher(
|
||||
session: session,
|
||||
scriptEngine: script,
|
||||
isScopeAlive: (_) => true,
|
||||
applyDiff: applied.add,
|
||||
);
|
||||
|
||||
dispatcher
|
||||
..enqueue(const RuntimeEvent(type: 'tap', target: 'a'))
|
||||
..enqueue(const RuntimeEvent(type: 'tap', target: 'b'));
|
||||
|
||||
await Future<void>.delayed(Duration.zero);
|
||||
|
||||
expect(script.events.map((event) => event.target), ['a', 'b']);
|
||||
expect(applied, hasLength(2));
|
||||
});
|
||||
|
||||
test('drops events for removed scope', () async {
|
||||
final session = _activeSession();
|
||||
final script = _FakeScriptEngine();
|
||||
var alive = true;
|
||||
final dispatcher = RuntimeEventDispatcher(
|
||||
session: session,
|
||||
scriptEngine: script,
|
||||
isScopeAlive: (_) => alive,
|
||||
applyDiff: (_) {},
|
||||
);
|
||||
|
||||
dispatcher.enqueue(const RuntimeEvent(type: 'tap', scope: 'dialog'));
|
||||
alive = false;
|
||||
|
||||
await Future<void>.delayed(Duration.zero);
|
||||
|
||||
expect(script.events, isEmpty);
|
||||
});
|
||||
|
||||
test('drops events with stale target epoch', () async {
|
||||
final session = _activeSession();
|
||||
final script = _FakeScriptEngine();
|
||||
var currentEpoch = 2;
|
||||
final dispatcher = RuntimeEventDispatcher(
|
||||
session: session,
|
||||
scriptEngine: script,
|
||||
isScopeAlive: (_) => true,
|
||||
isNodeEpochAlive: (_, epoch) => epoch == currentEpoch,
|
||||
applyDiff: (_) {},
|
||||
);
|
||||
|
||||
dispatcher.enqueue(
|
||||
const RuntimeEvent(type: 'tap', target: 'button', targetEpoch: 1),
|
||||
);
|
||||
currentEpoch = 3;
|
||||
|
||||
await Future<void>.delayed(Duration.zero);
|
||||
|
||||
expect(script.events, isEmpty);
|
||||
});
|
||||
|
||||
test('drops queued events after dispose', () async {
|
||||
final session = _activeSession();
|
||||
final script = _FakeScriptEngine();
|
||||
final dispatcher = RuntimeEventDispatcher(
|
||||
session: session,
|
||||
scriptEngine: script,
|
||||
isScopeAlive: (_) => true,
|
||||
applyDiff: (_) {},
|
||||
);
|
||||
|
||||
dispatcher.enqueue(const RuntimeEvent(type: 'tap'));
|
||||
dispatcher.dispose();
|
||||
|
||||
await Future<void>.delayed(Duration.zero);
|
||||
|
||||
expect(script.events, isEmpty);
|
||||
});
|
||||
|
||||
test('drops queued events after session dispose', () async {
|
||||
final session = _activeSession();
|
||||
final script = _FakeScriptEngine();
|
||||
final dispatcher = RuntimeEventDispatcher(
|
||||
session: session,
|
||||
scriptEngine: script,
|
||||
isScopeAlive: (_) => true,
|
||||
applyDiff: (_) {},
|
||||
);
|
||||
|
||||
dispatcher.enqueue(const RuntimeEvent(type: 'tap'));
|
||||
session.dispose();
|
||||
|
||||
await Future<void>.delayed(Duration.zero);
|
||||
|
||||
expect(script.events, isEmpty);
|
||||
});
|
||||
|
||||
test('continues draining after a script error', () async {
|
||||
final session = _activeSession();
|
||||
final script = _FakeScriptEngine()..failNext = true;
|
||||
final errors = <Object>[];
|
||||
final diagnostics = RuntimeDiagnostics();
|
||||
final dispatcher = RuntimeEventDispatcher(
|
||||
session: session,
|
||||
scriptEngine: script,
|
||||
isScopeAlive: (_) => true,
|
||||
applyDiff: (_) {},
|
||||
diagnostics: diagnostics,
|
||||
onError: errors.add,
|
||||
);
|
||||
|
||||
dispatcher
|
||||
..enqueue(const RuntimeEvent(type: 'tap', target: 'bad'))
|
||||
..enqueue(const RuntimeEvent(type: 'tap', target: 'good'));
|
||||
|
||||
await Future<void>.delayed(Duration.zero);
|
||||
|
||||
expect(errors, hasLength(1));
|
||||
expect(diagnostics.entries, hasLength(1));
|
||||
expect(
|
||||
diagnostics.entries.single.type,
|
||||
RuntimeDiagnosticType.luaEventError,
|
||||
);
|
||||
expect(diagnostics.entries.single.context['target'], 'bad');
|
||||
expect(script.events.map((event) => event.target), ['bad', 'good']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
RuntimeSession _activeSession() {
|
||||
final session = RuntimeSession(gameId: 'test')..beginLoading();
|
||||
session.activate();
|
||||
return session;
|
||||
}
|
||||
|
||||
class _FakeScriptEngine implements ScriptEngine {
|
||||
final events = <RuntimeEvent>[];
|
||||
bool failNext = false;
|
||||
|
||||
@override
|
||||
Future<void> loadPackage(GamePackage package) async {}
|
||||
|
||||
@override
|
||||
bool smokeTest(Map<String, Object?> context) => true;
|
||||
|
||||
@override
|
||||
GameDiff init(Map<String, Object?> context) => GameDiff.empty;
|
||||
|
||||
@override
|
||||
GameDiff dispatchEvent(RuntimeEvent event) {
|
||||
events.add(event);
|
||||
if (failNext) {
|
||||
failNext = false;
|
||||
throw StateError('boom');
|
||||
}
|
||||
return GameDiff.empty;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user