fix(runtime): harden application service boundaries

This commit is contained in:
edde746
2026-07-24 03:46:46 +02:00
parent 658da37b48
commit e0bf66eea8
309 changed files with 32574 additions and 4369 deletions
+110
View File
@@ -287,4 +287,114 @@ void main() {
},
);
});
for (final channel in [
(label: 'video', method: 'com.plezy/mpv_player', events: 'com.plezy/mpv_player/events', audio: false),
(label: 'audio', method: 'com.plezy/mpv_audio_player', events: 'com.plezy/mpv_audio_player/events', audio: true),
]) {
group('${channel.label} property bridge', () {
test('propagates SET_PROPERTY_FAILED', () async {
final calls = <MethodCall>[];
await withMockPlayerChannels(
methodChannelName: channel.method,
eventChannelName: channel.events,
methodHandler: (call) async {
calls.add(call);
if (call.method == 'initialize') return true;
if (call.method == 'setProperty') {
final arguments = call.arguments as Map;
if (arguments['name'] == 'unsupported-property') {
throw PlatformException(code: 'SET_PROPERTY_FAILED', message: 'Property write rejected');
}
}
return null;
},
testBody: () async {
final player = channel.audio ? PlayerNative.audio() : PlayerNative();
try {
await expectLater(
player.setProperty('unsupported-property', 'invalid'),
throwsA(isA<PlatformException>().having((error) => error.code, 'code', 'SET_PROPERTY_FAILED')),
);
final initializeIndex = calls.indexWhere((call) => call.method == 'initialize');
final propertyIndex = calls.indexWhere(
(call) => call.method == 'setProperty' && (call.arguments as Map)['name'] == 'unsupported-property',
);
expect(initializeIndex, isNonNegative);
expect(propertyIndex, greaterThan(initializeIndex));
} finally {
await player.dispose();
}
},
);
});
test('failed setVolume leaves published volume unchanged', () async {
await withMockPlayerChannels(
methodChannelName: channel.method,
eventChannelName: channel.events,
methodHandler: (call) async {
if (call.method == 'initialize') return true;
if (call.method == 'setProperty') {
final arguments = call.arguments as Map;
if (arguments['name'] == 'volume') {
throw PlatformException(code: 'SET_PROPERTY_FAILED', message: 'Property write rejected');
}
}
return null;
},
testBody: () async {
final player = channel.audio ? PlayerNative.audio() : PlayerNative();
try {
final initialVolume = player.state.volume;
await expectLater(
player.setVolume(37),
throwsA(isA<PlatformException>().having((error) => error.code, 'code', 'SET_PROPERTY_FAILED')),
);
expect(player.state.volume, initialVolume);
} finally {
await player.dispose();
}
},
);
});
test('successful setVolume publishes only after the accepted write', () async {
final volumeWriteStarted = Completer<void>();
final acceptVolumeWrite = Completer<void>();
await withMockPlayerChannels(
methodChannelName: channel.method,
eventChannelName: channel.events,
methodHandler: (call) async {
if (call.method == 'initialize') return true;
if (call.method == 'setProperty') {
final arguments = call.arguments as Map;
if (arguments['name'] == 'volume') {
volumeWriteStarted.complete();
await acceptVolumeWrite.future;
}
}
return null;
},
testBody: () async {
final player = channel.audio ? PlayerNative.audio() : PlayerNative();
try {
final initialVolume = player.state.volume;
final write = player.setVolume(42);
await volumeWriteStarted.future;
expect(player.state.volume, initialVolume);
acceptVolumeWrite.complete();
await write;
expect(player.state.volume, 42);
} finally {
if (!acceptVolumeWrite.isCompleted) acceptVolumeWrite.complete();
await player.dispose();
}
},
);
});
});
}
}