chore: adopt Dart 3.9 toolchain — honest floor + tall-style reformat (T-353)
Raise the declared minimums in pubspec.yaml to what our deps already require: Flutter >=3.35.0 / Dart >=3.9.0 (was 3.19.0 / 3.5.0). alchemist 0.12 needs Flutter 3.32; Dart 3.9 first ships in Flutter 3.35, so 3.35 is the binding floor. Pin the exact build toolchain in .fvmrc (Flutter 3.44.1). Moving to the Dart 3.9 language level switches `dart format` to the new "tall" style and enables two new lints. This commit is the resulting mechanical churn, isolated from any behaviour change: - whole-tree `dart format` reformat (tall style) - `dart fix` for unnecessary_underscores + use_null_aware_elements No runtime behaviour change; `make test` green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,53 +4,41 @@ import 'package:clide/kernel/kernel.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
ThemeDefinition _def(String name, Color primary) => ThemeDefinition(
|
||||
name: name,
|
||||
displayName: name,
|
||||
dark: true,
|
||||
palette: Palette({
|
||||
'primary': primary,
|
||||
'accent': primary,
|
||||
'background': const Color(0xFF000000),
|
||||
'surface': const Color(0xFF111111),
|
||||
'panel': const Color(0xFF222222),
|
||||
'foreground': const Color(0xFFFFFFFF),
|
||||
'success': const Color(0xFF00FF00),
|
||||
'warning': const Color(0xFFFFFF00),
|
||||
'error': const Color(0xFFFF0000),
|
||||
}),
|
||||
);
|
||||
name: name,
|
||||
displayName: name,
|
||||
dark: true,
|
||||
palette: Palette({
|
||||
'primary': primary,
|
||||
'accent': primary,
|
||||
'background': const Color(0xFF000000),
|
||||
'surface': const Color(0xFF111111),
|
||||
'panel': const Color(0xFF222222),
|
||||
'foreground': const Color(0xFFFFFFFF),
|
||||
'success': const Color(0xFF00FF00),
|
||||
'warning': const Color(0xFFFFFF00),
|
||||
'error': const Color(0xFFFF0000),
|
||||
}),
|
||||
);
|
||||
|
||||
void main() {
|
||||
group('ThemeController', () {
|
||||
test('starts on first bundled theme', () {
|
||||
final c = ThemeController(bundled: [
|
||||
_def('a', const Color(0xFF111111)),
|
||||
_def('b', const Color(0xFF222222)),
|
||||
]);
|
||||
final c = ThemeController(bundled: [_def('a', const Color(0xFF111111)), _def('b', const Color(0xFF222222))]);
|
||||
expect(c.currentName, 'a');
|
||||
});
|
||||
|
||||
test('honors initialName when present', () {
|
||||
final c = ThemeController(
|
||||
bundled: [_def('a', const Color(0xFF000000)), _def('b', const Color(0xFF999999))],
|
||||
initialName: 'b',
|
||||
);
|
||||
final c = ThemeController(bundled: [_def('a', const Color(0xFF000000)), _def('b', const Color(0xFF999999))], initialName: 'b');
|
||||
expect(c.currentName, 'b');
|
||||
});
|
||||
|
||||
test('silently falls back to first when initialName is unknown', () {
|
||||
final c = ThemeController(
|
||||
bundled: [_def('a', const Color(0xFF000000))],
|
||||
initialName: 'missing',
|
||||
);
|
||||
final c = ThemeController(bundled: [_def('a', const Color(0xFF000000))], initialName: 'missing');
|
||||
expect(c.currentName, 'a');
|
||||
});
|
||||
|
||||
test('select changes current + notifies listeners', () {
|
||||
final c = ThemeController(bundled: [
|
||||
_def('a', const Color(0xFF000000)),
|
||||
_def('b', const Color(0xFF333333)),
|
||||
]);
|
||||
final c = ThemeController(bundled: [_def('a', const Color(0xFF000000)), _def('b', const Color(0xFF333333))]);
|
||||
var count = 0;
|
||||
c.addListener(() => count++);
|
||||
c.select('b');
|
||||
|
||||
@@ -48,31 +48,19 @@ surface:
|
||||
panel.background: "semantic.mainchrome"
|
||||
panel.border: red
|
||||
''');
|
||||
expect(def.surfaceOverride, {
|
||||
'panel.background': 'semantic.mainchrome',
|
||||
'panel.border': 'red',
|
||||
});
|
||||
expect(def.surfaceOverride, {'panel.background': 'semantic.mainchrome', 'panel.border': 'red'});
|
||||
});
|
||||
|
||||
test('throws when name is missing and no fallback', () {
|
||||
expect(
|
||||
() => loader.fromYamlString('palette: { fg: "#fff" }'),
|
||||
throwsA(isA<FormatException>()),
|
||||
);
|
||||
expect(() => loader.fromYamlString('palette: { fg: "#fff" }'), throwsA(isA<FormatException>()));
|
||||
});
|
||||
|
||||
test('throws when palette is missing', () {
|
||||
expect(
|
||||
() => loader.fromYamlString('name: t'),
|
||||
throwsA(isA<FormatException>()),
|
||||
);
|
||||
expect(() => loader.fromYamlString('name: t'), throwsA(isA<FormatException>()));
|
||||
});
|
||||
|
||||
test('fallback name is used when name is absent', () {
|
||||
final def = loader.fromYamlString(
|
||||
'palette: { fg: "#fff" }',
|
||||
fallbackName: 'inferred',
|
||||
);
|
||||
final def = loader.fromYamlString('palette: { fg: "#fff" }', fallbackName: 'inferred');
|
||||
expect(def.name, 'inferred');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,32 +37,40 @@ void main() {
|
||||
);
|
||||
addTearDown(controller.dispose);
|
||||
late ClideThemeData captured;
|
||||
await tester.pumpWidget(Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ClideTheme(
|
||||
controller: controller,
|
||||
child: Builder(builder: (ctx) {
|
||||
captured = ClideTheme.of(ctx);
|
||||
return const SizedBox();
|
||||
}),
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ClideTheme(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (ctx) {
|
||||
captured = ClideTheme.of(ctx);
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
);
|
||||
expect(captured, isNotNull);
|
||||
});
|
||||
|
||||
testWidgets('of() throws when no ClideTheme ancestor', (tester) async {
|
||||
late Object captured;
|
||||
await tester.pumpWidget(Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Builder(builder: (ctx) {
|
||||
try {
|
||||
ClideTheme.of(ctx);
|
||||
} catch (e) {
|
||||
captured = e;
|
||||
}
|
||||
return const SizedBox();
|
||||
}),
|
||||
));
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Builder(
|
||||
builder: (ctx) {
|
||||
try {
|
||||
ClideTheme.of(ctx);
|
||||
} catch (e) {
|
||||
captured = e;
|
||||
}
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(captured, isA<FlutterError>());
|
||||
});
|
||||
|
||||
@@ -90,32 +98,40 @@ void main() {
|
||||
);
|
||||
addTearDown(controller.dispose);
|
||||
late ThemeController captured;
|
||||
await tester.pumpWidget(Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ClideTheme(
|
||||
controller: controller,
|
||||
child: Builder(builder: (ctx) {
|
||||
captured = ClideTheme.controllerOf(ctx);
|
||||
return const SizedBox();
|
||||
}),
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ClideTheme(
|
||||
controller: controller,
|
||||
child: Builder(
|
||||
builder: (ctx) {
|
||||
captured = ClideTheme.controllerOf(ctx);
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
);
|
||||
expect(captured, same(controller));
|
||||
});
|
||||
|
||||
testWidgets('controllerOf() throws when no ClideTheme ancestor', (tester) async {
|
||||
late Object captured;
|
||||
await tester.pumpWidget(Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Builder(builder: (ctx) {
|
||||
try {
|
||||
ClideTheme.controllerOf(ctx);
|
||||
} catch (e) {
|
||||
captured = e;
|
||||
}
|
||||
return const SizedBox();
|
||||
}),
|
||||
));
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Builder(
|
||||
builder: (ctx) {
|
||||
try {
|
||||
ClideTheme.controllerOf(ctx);
|
||||
} catch (e) {
|
||||
captured = e;
|
||||
}
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(captured, isA<FlutterError>());
|
||||
});
|
||||
});
|
||||
@@ -133,11 +149,7 @@ void main() {
|
||||
|
||||
test('ContrastFailure.toString embeds the pair name, ratio, and minimum', () {
|
||||
const failure = ContrastFailure(
|
||||
pair: ContrastPair(
|
||||
name: 'global.text_on_background',
|
||||
foreground: Color(0xFF888888),
|
||||
background: Color(0xFF7F7F7F),
|
||||
),
|
||||
pair: ContrastPair(name: 'global.text_on_background', foreground: Color(0xFF888888), background: Color(0xFF7F7F7F)),
|
||||
ratio: 1.23,
|
||||
minimum: 4.5,
|
||||
);
|
||||
@@ -150,16 +162,11 @@ void main() {
|
||||
|
||||
group('ThemeLoader error + file paths', () {
|
||||
test('fromYamlString throws when the root is not a map', () {
|
||||
expect(
|
||||
() => const ThemeLoader().fromYamlString('- this\n- is\n- a list'),
|
||||
throwsA(isA<FormatException>()),
|
||||
);
|
||||
expect(() => const ThemeLoader().fromYamlString('- this\n- is\n- a list'), throwsA(isA<FormatException>()));
|
||||
});
|
||||
|
||||
test('fromFile loads the same content as fromYamlString', () async {
|
||||
final tmp = await File.fromUri(
|
||||
Uri.file('${Directory.systemTemp.path}/clide-theme-${DateTime.now().microsecondsSinceEpoch}.yaml'),
|
||||
).create();
|
||||
final tmp = await File.fromUri(Uri.file('${Directory.systemTemp.path}/clide-theme-${DateTime.now().microsecondsSinceEpoch}.yaml')).create();
|
||||
addTearDown(() async {
|
||||
if (tmp.existsSync()) await tmp.delete();
|
||||
});
|
||||
@@ -184,18 +191,12 @@ palette:
|
||||
|
||||
group('Palette / SemanticRoles iterables', () {
|
||||
test('Palette.names yields every registered colour key', () {
|
||||
final p = Palette(const {
|
||||
'primary': Color(0xFF000000),
|
||||
'accent': Color(0xFFFFFFFF),
|
||||
});
|
||||
final p = Palette(const {'primary': Color(0xFF000000), 'accent': Color(0xFFFFFFFF)});
|
||||
expect(p.names, containsAll(['primary', 'accent']));
|
||||
});
|
||||
|
||||
test('SemanticRoles.roles yields every registered role key', () {
|
||||
final s = SemanticRoles(const {
|
||||
'text': Color(0xFFFFFFFF),
|
||||
'background': Color(0xFF000000),
|
||||
});
|
||||
final s = SemanticRoles(const {'text': Color(0xFFFFFFFF), 'background': Color(0xFF000000)});
|
||||
expect(s.roles, containsAll(['text', 'background']));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -82,9 +82,7 @@ void main() {
|
||||
'err': Color(0xFFFF0000),
|
||||
'info': Color(0xFF111111),
|
||||
}),
|
||||
surfaceOverride: const {
|
||||
'panel.background': '#00FF00',
|
||||
},
|
||||
surfaceOverride: const {'panel.background': '#00FF00'},
|
||||
);
|
||||
expect(tokens.panelBackground, const Color(0xFF00FF00));
|
||||
});
|
||||
@@ -103,9 +101,7 @@ void main() {
|
||||
'err': Color(0xFFFF0000),
|
||||
'info': Color(0xFF111111),
|
||||
}),
|
||||
semanticOverride: const SemanticRoles({
|
||||
'focus': Color(0xFF007777),
|
||||
}),
|
||||
semanticOverride: const SemanticRoles({'focus': Color(0xFF007777)}),
|
||||
);
|
||||
// No 'accent' in palette, so globalFocus falls through to
|
||||
// semantic.focus which is overridden.
|
||||
@@ -122,9 +118,7 @@ void main() {
|
||||
'textHi': Color(0xFFFFFFFF),
|
||||
'accent': Color(0xFF111111),
|
||||
}),
|
||||
extensionOverride: const {
|
||||
'ext.sqlite.table.background': '#ABCDEF',
|
||||
},
|
||||
extensionOverride: const {'ext.sqlite.table.background': '#ABCDEF'},
|
||||
);
|
||||
expect(tokens.extensionTokens['ext.sqlite.table.background'], const Color(0xFFABCDEF));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user