Skip to content

Commit 88897f6

Browse files
committed
update
1 parent dff0de1 commit 88897f6

2 files changed

Lines changed: 336 additions & 0 deletions

File tree

test/generator_emit_test.dart

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
//.title
2+
// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
3+
//
4+
// Copyright © dev-cetera.com & contributors.
5+
// MIT license. See https://opensource.org/license/mit
6+
//
7+
// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
8+
//
9+
// Source-level tests for the *generator* source code itself
10+
// (generate_screen, generate_screen_bindings, generate_screen_access). We
11+
// can't run them headlessly without analyzer scaffolding, so we test the
12+
// emitter functions / branches we can statically.
13+
14+
import 'dart:io';
15+
16+
import 'package:test/test.dart';
17+
18+
void main() {
19+
final bindingsSrc =
20+
File('lib/src/generate_screen_bindings.dart').readAsStringSync();
21+
final accessSrc =
22+
File('lib/src/generate_screen_access.dart').readAsStringSync();
23+
final screenSrc = File('lib/src/generate_screen.dart').readAsStringSync();
24+
25+
group('Generator source sanity', () {
26+
test('generate_screen_bindings.dart has a top-level public function', () {
27+
expect(
28+
bindingsSrc,
29+
contains('Future<void> generateScreenBindings('),
30+
);
31+
});
32+
33+
test('generate_screen_access.dart has a top-level public function', () {
34+
expect(
35+
accessSrc,
36+
contains('Future<void> generateScreenAccess('),
37+
);
38+
});
39+
40+
test('generate_screen.dart has a top-level public function', () {
41+
expect(screenSrc, contains('Future<void> generateScreen('));
42+
});
43+
});
44+
45+
group('Conflict-detection branches in interpolator', () {
46+
test('rejects isAccessibleOnlyIfLoggedInAndVerified + '
47+
'isAccessibleOnlyIfLoggedIn both true', () {
48+
expect(
49+
bindingsSrc,
50+
contains(
51+
'Cannot set both `isAccessibleOnlyIfLoggedInAndVerified` and '
52+
'`isAccessibleOnlyIfLoggedIn` to `true`.',
53+
),
54+
);
55+
});
56+
57+
test('rejects isAccessibleOnlyIfLoggedInAndVerified + '
58+
'isAccessibleOnlyIfLoggedOut both true', () {
59+
expect(
60+
bindingsSrc,
61+
contains(
62+
'Cannot set both `isAccessibleOnlyIfLoggedInAndVerified` and '
63+
'`isAccessibleOnlyIfLoggedOut` to `true`.',
64+
),
65+
);
66+
});
67+
68+
test('rejects isAccessibleOnlyIfLoggedIn + isAccessibleOnlyIfLoggedOut '
69+
'both true', () {
70+
expect(
71+
bindingsSrc,
72+
contains(
73+
'Cannot set both `isAccessibleOnlyIfLoggedIn` and '
74+
'`isAccessibleOnlyIfLoggedOut` to `true`.',
75+
),
76+
);
77+
});
78+
79+
test('rejects isRedirectable + required internalParameters', () {
80+
expect(
81+
bindingsSrc,
82+
contains(
83+
'Cannot set `isRedirectable` to `true` if `internalParameters` '
84+
'contains required parameters.',
85+
),
86+
);
87+
});
88+
});
89+
90+
group('Emitter helpers reference the right df_screen symbols', () {
91+
test('___IP3_V2___ accesses .superScreen!.routeState!', () {
92+
// The original failure caught a stray ')'. Re-check the emitted
93+
// line in case it regresses.
94+
final lines = bindingsSrc.split('\n');
95+
final ipIdx = lines.indexWhere((l) => l.contains('___IP3_V2___'));
96+
expect(ipIdx, isNot(-1));
97+
final retIdx = lines.indexWhere(
98+
(l) => l.contains('super.superScreen!.routeState!.'),
99+
ipIdx,
100+
);
101+
expect(retIdx, isNot(-1));
102+
final line = lines[retIdx];
103+
var open = 0, close = 0;
104+
for (final ch in line.split('')) {
105+
if (ch == '(') open++;
106+
if (ch == ')') close++;
107+
}
108+
expect(open, close, reason: 'Emitter line has unbalanced parens');
109+
});
110+
111+
test('___QP3_V2___ reads from superScreen?.routeState?.uri', () {
112+
expect(
113+
bindingsSrc,
114+
contains('super.superScreen?.routeState?.uri.queryParameters'),
115+
);
116+
});
117+
});
118+
}

test/templates_test.dart

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
//.title
2+
// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
3+
//
4+
// Copyright © dev-cetera.com & contributors.
5+
// MIT license. See https://opensource.org/license/mit
6+
//
7+
// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
8+
//
9+
// Template structure tests for df_generate_screen v2 templates. The
10+
// templates are .md files that wrap Dart inside ```dart fences, then are
11+
// run through the TemplateInterpolator on insight extraction.
12+
//
13+
// We verify here that:
14+
// - every template file exists and has a non-trivial body
15+
// - the placeholder set used by each template matches what the generator
16+
// supplies via lib/src/generate_screen_bindings.dart
17+
// - emitted Dart has balanced braces/parens (a stray `)` is what
18+
// template_strings_test originally caught)
19+
20+
import 'dart:io';
21+
22+
import 'package:test/test.dart';
23+
24+
const _templatesDir = 'templates/v2';
25+
26+
void main() {
27+
group('Template files exist', () {
28+
test('_state.dart.md', () {
29+
expect(File('$_templatesDir/_state.dart.md').existsSync(), isTrue);
30+
});
31+
test('_controller.dart.md', () {
32+
expect(File('$_templatesDir/_controller.dart.md').existsSync(), isTrue);
33+
});
34+
test('widget.dart.md', () {
35+
expect(File('$_templatesDir/widget.dart.md').existsSync(), isTrue);
36+
});
37+
test('_bindings.g.dart.md', () {
38+
expect(File('$_templatesDir/_bindings.g.dart.md').existsSync(), isTrue);
39+
});
40+
test('_access.g.dart.md', () {
41+
expect(File('$_templatesDir/_access.g.dart.md').existsSync(), isTrue);
42+
});
43+
});
44+
45+
group('widget.dart.md placeholders', () {
46+
final src = File('$_templatesDir/widget.dart.md').readAsStringSync();
47+
test('declares the screen class with ___WIDGET_NAME___', () {
48+
expect(src, contains('___WIDGET_NAME___'));
49+
});
50+
test('uses the base class ____WIDGET_NAME___', () {
51+
expect(src, contains('extends ____WIDGET_NAME___'));
52+
});
53+
test('parts in _bindings.g.dart, _controller.dart, _state.dart', () {
54+
expect(src, contains("part '_bindings.g.dart';"));
55+
expect(src, contains("part '_controller.dart';"));
56+
expect(src, contains("part '_state.dart';"));
57+
});
58+
test('passes routeState through to super', () {
59+
expect(src, contains('super.routeState'));
60+
});
61+
});
62+
63+
group('_bindings.g.dart.md structure', () {
64+
final src = File('$_templatesDir/_bindings.g.dart.md').readAsStringSync();
65+
test('has placeholders for query+internal parameters', () {
66+
for (final ph in const [
67+
'___WIDGET_NAME___',
68+
'___IP0_V2___',
69+
'___IP1___',
70+
'___QP0_V2___',
71+
'___QP1_V2___',
72+
'___QP2_V2___',
73+
'___QP3_V2___',
74+
'___CONDITION___',
75+
'___SCREEN_SEGMENT___',
76+
'___DEFAULT_TITLE___',
77+
]) {
78+
expect(src, contains(ph), reason: 'missing placeholder $ph');
79+
}
80+
});
81+
82+
test('emits RouteState<X?> with nullable extra type', () {
83+
expect(src, contains('RouteState<___WIDGET_NAME___Extra?>'));
84+
});
85+
86+
test('emits RouteBuilder<X?> with nullable extra type', () {
87+
expect(src, contains('extends RouteBuilder<___WIDGET_NAME___Extra?>'));
88+
});
89+
90+
test('emits Screen<X?> base class with nullable extra type', () {
91+
expect(src, contains('extends Screen<___WIDGET_NAME___Extra?>'));
92+
});
93+
});
94+
95+
group('_access.g.dart.md structure', () {
96+
final src = File('$_templatesDir/_access.g.dart.md').readAsStringSync();
97+
98+
test('declares the three auth-check helpers', () {
99+
for (final fn in const [
100+
'isLoggedInAndEmailVerified',
101+
'isLoggedIn',
102+
'isLoggedOut',
103+
]) {
104+
expect(src, contains('bool $fn()'),
105+
reason: 'missing helper $fn',);
106+
}
107+
});
108+
109+
test('emits a registry placeholder ___ROUTE_BUILDERS___', () {
110+
expect(src, contains('___ROUTE_BUILDERS___'));
111+
});
112+
113+
test('declares EmptyScreenState and ErrorScreenState', () {
114+
expect(src, contains('EmptyScreenState extends RouteState'));
115+
expect(src, contains('ErrorScreenState extends RouteState<Enum>'));
116+
});
117+
});
118+
119+
group('Template Dart syntax sanity', () {
120+
File templateFile(String name) =>
121+
File('$_templatesDir/$name');
122+
123+
void expectBalanced(String src, String label) {
124+
// Strip markdown fence + placeholders to make brace counting more
125+
// accurate.
126+
final code = src
127+
.replaceAll(RegExp(r'```dart\n?'), '')
128+
.replaceAll(RegExp(r'```'), '')
129+
.replaceAll(RegExp(r'___[A-Z0-9_]+___'), 'PH');
130+
var braces = 0, parens = 0, brackets = 0;
131+
for (var i = 0; i < code.length; i++) {
132+
final ch = code[i];
133+
if (ch == '{') braces++;
134+
if (ch == '}') braces--;
135+
if (ch == '(') parens++;
136+
if (ch == ')') parens--;
137+
if (ch == '[') brackets++;
138+
if (ch == ']') brackets--;
139+
}
140+
expect(braces, 0, reason: '$label: unbalanced {}');
141+
expect(parens, 0, reason: '$label: unbalanced ()');
142+
expect(brackets, 0, reason: '$label: unbalanced []');
143+
}
144+
145+
test('widget.dart.md has balanced delimiters', () {
146+
expectBalanced(
147+
templateFile('widget.dart.md').readAsStringSync(),
148+
'widget.dart.md',
149+
);
150+
});
151+
152+
test('_bindings.g.dart.md has balanced delimiters', () {
153+
expectBalanced(
154+
templateFile('_bindings.g.dart.md').readAsStringSync(),
155+
'_bindings.g.dart.md',
156+
);
157+
});
158+
159+
test('_access.g.dart.md has balanced delimiters', () {
160+
expectBalanced(
161+
templateFile('_access.g.dart.md').readAsStringSync(),
162+
'_access.g.dart.md',
163+
);
164+
});
165+
166+
test('_state.dart.md has balanced delimiters', () {
167+
expectBalanced(
168+
templateFile('_state.dart.md').readAsStringSync(),
169+
'_state.dart.md',
170+
);
171+
});
172+
173+
test('_controller.dart.md has balanced delimiters', () {
174+
expectBalanced(
175+
templateFile('_controller.dart.md').readAsStringSync(),
176+
'_controller.dart.md',
177+
);
178+
});
179+
});
180+
181+
group('Interpolator placeholder coverage', () {
182+
final src = File('lib/src/generate_screen_bindings.dart').readAsStringSync();
183+
184+
final wellKnownPlaceholders = {
185+
'___WIDGET_NAME___',
186+
'___SCREEN_KEY___',
187+
'___SCREEN_SEGMENT___',
188+
'___SCREEN_PATH___',
189+
'___SCREEN_CONST_KEY___',
190+
'___CONDITION___',
191+
'___DEFAULT_TITLE___',
192+
'___IS_REDIRECTABLE___',
193+
'___IS_ACCESSIBLE_ONLY_IF_LOGGED_IN_AND_VERIFIED___',
194+
'___IS_ACCESSIBLE_ONLY_IF_LOGGED_IN___',
195+
'___IS_ACCESSIBLE_ONLY_IF_LOGGED_OUT___',
196+
'___IS_ALWAYS_ACCESSIBLE___',
197+
'___IP0_V2___',
198+
'___IP0___',
199+
'___IP1___',
200+
'___IP2___',
201+
'___IP3_V2___',
202+
'___QP0_V2___',
203+
'___QP0___',
204+
'___QP1_V2___',
205+
'___QP1___',
206+
'___QP2_V2___',
207+
'___QP2___',
208+
'___QP3_V2___',
209+
};
210+
211+
for (final ph in wellKnownPlaceholders) {
212+
test('generate_screen_bindings.dart registers $ph', () {
213+
expect(src, contains("'$ph'"),
214+
reason: '$ph should appear as a registered interpolator key',);
215+
});
216+
}
217+
});
218+
}

0 commit comments

Comments
 (0)