Skip to content

Commit a75d478

Browse files
committed
[red] expose stale editor board operations across revisions and sessions
Signed-off-by: Viwat Vchirawongkwin <viwat.v@chula.ac.th>
1 parent 8dde8d6 commit a75d478

1 file changed

Lines changed: 127 additions & 0 deletions

File tree

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// SPDX-License-Identifier: MIT
2+
// Part of PyBLE (https://pyble.dev) — see /LICENSE.
3+
4+
import 'dart:async';
5+
import 'dart:convert';
6+
import 'dart:typed_data';
7+
import 'package:flutter_riverpod/flutter_riverpod.dart';
8+
import 'package:flutter_test/flutter_test.dart';
9+
import 'package:pyble/app/providers.dart';
10+
import 'package:pyble/editor/editor.dart';
11+
import 'package:pyble/files/files.dart';
12+
import 'package:pyble/pble/pble.dart';
13+
import '../support/recording_connection.dart';
14+
15+
class HeldConnection extends RecordingConnection
16+
implements ConnectionSessionStampSource {
17+
HeldConnection() : super(initial: ConnState.ready);
18+
Object stamp = Object();
19+
@override
20+
Object get connectionSessionStamp => stamp;
21+
final entered = Completer<void>();
22+
final release = Completer<void>();
23+
bool holdPut = true;
24+
bool holdGet = false;
25+
@override
26+
Future<void> putFile(
27+
String path,
28+
Uint8List bytes, {
29+
ProgressCb? onProgress,
30+
}) async {
31+
await super.putFile(path, bytes, onProgress: onProgress);
32+
if (holdPut) {
33+
if (!entered.isCompleted) entered.complete();
34+
await release.future;
35+
}
36+
}
37+
38+
@override
39+
Future<Uint8List> getFile(String path, {ProgressCb? onProgress}) async {
40+
final result = await super.getFile(path, onProgress: onProgress);
41+
if (holdGet) {
42+
if (!entered.isCompleted) entered.complete();
43+
await release.future;
44+
}
45+
return result;
46+
}
47+
}
48+
49+
void main() {
50+
ProviderContainer bind(HeldConnection connection) {
51+
final c = ProviderContainer(
52+
overrides: [connectionProvider.overrideWithValue(connection)],
53+
);
54+
addTearDown(c.dispose);
55+
addTearDown(() {
56+
if (!connection.release.isCompleted) connection.release.complete();
57+
});
58+
return c;
59+
}
60+
61+
test('Save completion cannot clear an edit-away/back revision', () async {
62+
final connection = HeldConnection();
63+
final c = bind(connection);
64+
final doc = c.read(editorDocumentProvider.notifier)..setContent('original');
65+
final save = c.read(saveControllerProvider).save();
66+
await connection.entered.future;
67+
doc.setContent('newer');
68+
doc.setContent('original');
69+
connection.release.complete();
70+
await save;
71+
expect(c.read(editorDocumentProvider).dirty, isTrue);
72+
expect(c.read(editorDocumentProvider).boardPath, isNull);
73+
});
74+
test('Run never dispatches second verb on a replaced attachment', () async {
75+
final connection = HeldConnection();
76+
final c = bind(connection);
77+
c.read(editorDocumentProvider.notifier).setContent('print(1)');
78+
final run = c.read(runControllerProvider).run();
79+
final result = expectLater(run, throwsA(isA<Exception>()));
80+
await connection.entered.future;
81+
connection.stamp = Object();
82+
connection.release.complete();
83+
await result;
84+
expect(connection.runFileCalls, isEmpty);
85+
expect(c.read(editorDocumentProvider).dirty, isTrue);
86+
});
87+
test(
88+
'Board Open refuses old GET after stable facade changes attachment',
89+
() async {
90+
final connection = HeldConnection()..holdPut = false;
91+
await connection.putFile(
92+
'/board.py',
93+
Uint8List.fromList(utf8.encode('old board')),
94+
);
95+
connection.holdGet = true;
96+
final c = bind(connection);
97+
final files = c.read(fileExplorerProvider.notifier);
98+
await pumpEventQueue();
99+
final open = files.openInEditor('board.py');
100+
await connection.entered.future;
101+
connection.stamp = Object();
102+
connection.release.complete();
103+
await open;
104+
expect(c.read(editorDocumentProvider).content, isEmpty);
105+
expect(c.read(editorDocumentProvider).boardPath, isNull);
106+
},
107+
);
108+
test(
109+
'Files upload completion cannot bind an edit-away/back revision',
110+
() async {
111+
final connection = HeldConnection();
112+
final c = bind(connection);
113+
final files = c.read(fileExplorerProvider.notifier);
114+
await pumpEventQueue();
115+
final doc = c.read(editorDocumentProvider.notifier)
116+
..setContent('original');
117+
final upload = files.uploadCurrentBuffer();
118+
await connection.entered.future;
119+
doc.setContent('newer');
120+
doc.setContent('original');
121+
connection.release.complete();
122+
await upload;
123+
expect(c.read(editorDocumentProvider).dirty, isTrue);
124+
expect(c.read(editorDocumentProvider).boardPath, isNull);
125+
},
126+
);
127+
}

0 commit comments

Comments
 (0)