The flow editor is a Ch∆In Studio sub-component (chain product), not a F∆I-vendor package. Rename the package, entry library file, and all package: imports. flutter analyze: clean. Signed-off-by: flemming-it <sf@flemming.it>
169 lines
5.6 KiB
Dart
169 lines
5.6 KiB
Dart
// Tests for FlowYamlCodeController's type-token recolouring.
|
|
//
|
|
// The controller post-processes the YAML highlighter's span
|
|
// tree to recolour any `key: <type>` value where the value is
|
|
// one of `text|json|bytes|file|number|integer` and the key sits
|
|
// at an indented depth (so top-level `name: text` doesn't
|
|
// false-match). We can't easily inspect TextSpan colours without
|
|
// rendering, so the tests below render the controller into a
|
|
// CodeField inside a TestWidget tree and walk the produced
|
|
// span tree.
|
|
|
|
import 'package:chain_studio_flow_editor/src/flow_yaml_controller.dart';
|
|
import 'package:chain_studio_flow_editor/src/wire_colors.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
group('FlowYamlCodeController type-token recoloring', () {
|
|
testWidgets('colours indented `field: bytes` value with bytes wire hue', (
|
|
tester,
|
|
) async {
|
|
final c = FlowYamlCodeController();
|
|
addTearDown(c.dispose);
|
|
c.fullText = '''
|
|
inputs:
|
|
document: bytes
|
|
''';
|
|
late TextSpan span;
|
|
late ThemeData theme;
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Builder(
|
|
builder: (context) {
|
|
theme = Theme.of(context);
|
|
span = c.buildTextSpan(context: context, withComposing: false);
|
|
return const SizedBox();
|
|
},
|
|
),
|
|
),
|
|
);
|
|
// Let CodeController's 500ms analyzer debounce fire so
|
|
// the test teardown isn't blocked by a pending timer.
|
|
await tester.pump(const Duration(seconds: 1));
|
|
|
|
final tokens = _flattenLeaves(span);
|
|
// Find the leaf whose text is the word "bytes" and assert
|
|
// it carries the wire-bytes colour from the shared palette.
|
|
final bytesLeaf = tokens.firstWhere(
|
|
(t) => t.text == 'bytes',
|
|
orElse: () => const _Leaf('', null),
|
|
);
|
|
expect(bytesLeaf.text, 'bytes', reason: 'expected a "bytes" leaf');
|
|
final expected = wireColor('bytes', theme);
|
|
expect(bytesLeaf.style?.color, expected);
|
|
expect(bytesLeaf.style?.fontWeight, FontWeight.w600);
|
|
});
|
|
|
|
testWidgets('does NOT recolour top-level `name: text` (not indented)', (
|
|
tester,
|
|
) async {
|
|
final c = FlowYamlCodeController();
|
|
addTearDown(c.dispose);
|
|
// The flow's top-level `name: hello` is also not a type
|
|
// declaration; we use `text` here to make the trap
|
|
// explicit. The leading `name:` is at column 0 — not
|
|
// indented — so the recolour must skip it.
|
|
c.fullText = 'name: text\n';
|
|
late TextSpan span;
|
|
late ThemeData theme;
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Builder(
|
|
builder: (context) {
|
|
theme = Theme.of(context);
|
|
span = c.buildTextSpan(context: context, withComposing: false);
|
|
return const SizedBox();
|
|
},
|
|
),
|
|
),
|
|
);
|
|
// Let CodeController's 500ms analyzer debounce fire so
|
|
// the test teardown isn't blocked by a pending timer.
|
|
await tester.pump(const Duration(seconds: 1));
|
|
|
|
final tokens = _flattenLeaves(span);
|
|
final textLeaf = tokens.firstWhere(
|
|
(t) => t.text == 'text',
|
|
orElse: () => const _Leaf('', null),
|
|
);
|
|
// At top level the highlighter does paint it as a string
|
|
// (green-ish, palette-derived), but it must NOT match the
|
|
// explicit wire-text hue + 600 weight combo our recolour
|
|
// applies — that's the signal we'd be incorrectly tagging
|
|
// it as a type declaration.
|
|
final wireText = wireColor('text', theme);
|
|
final isRecoloured =
|
|
textLeaf.style?.color == wireText &&
|
|
textLeaf.style?.fontWeight == FontWeight.w600;
|
|
expect(
|
|
isRecoloured,
|
|
isFalse,
|
|
reason: 'top-level `name: text` must not be flagged as a type decl',
|
|
);
|
|
});
|
|
|
|
testWidgets('colours `type: text` value (explicit-type module shape)', (
|
|
tester,
|
|
) async {
|
|
final c = FlowYamlCodeController();
|
|
addTearDown(c.dispose);
|
|
c.fullText = '''
|
|
inputs:
|
|
- name: pdf
|
|
type: bytes
|
|
''';
|
|
late TextSpan span;
|
|
late ThemeData theme;
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Builder(
|
|
builder: (context) {
|
|
theme = Theme.of(context);
|
|
span = c.buildTextSpan(context: context, withComposing: false);
|
|
return const SizedBox();
|
|
},
|
|
),
|
|
),
|
|
);
|
|
// Let CodeController's 500ms analyzer debounce fire so
|
|
// the test teardown isn't blocked by a pending timer.
|
|
await tester.pump(const Duration(seconds: 1));
|
|
|
|
final tokens = _flattenLeaves(span);
|
|
final bytesLeaves = tokens.where((t) => t.text == 'bytes').toList();
|
|
expect(bytesLeaves, isNotEmpty);
|
|
final expected = wireColor('bytes', theme);
|
|
// Every `bytes` leaf in this snippet is the type value of
|
|
// the `type: bytes` line.
|
|
for (final leaf in bytesLeaves) {
|
|
expect(leaf.style?.color, expected);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
class _Leaf {
|
|
final String text;
|
|
final TextStyle? style;
|
|
const _Leaf(this.text, this.style);
|
|
}
|
|
|
|
List<_Leaf> _flattenLeaves(InlineSpan span) {
|
|
final out = <_Leaf>[];
|
|
void visit(InlineSpan s, TextStyle? inherited) {
|
|
if (s is! TextSpan) return;
|
|
final merged = inherited == null
|
|
? s.style
|
|
: (s.style == null ? inherited : inherited.merge(s.style));
|
|
final t = s.text;
|
|
if (t != null && t.isNotEmpty) out.add(_Leaf(t, merged));
|
|
final children = s.children;
|
|
if (children != null) {
|
|
for (final c in children) visit(c, merged);
|
|
}
|
|
}
|
|
|
|
visit(span, null);
|
|
return out;
|
|
}
|