Files
buzz/mobile/test/shared/theme/theme_pairs_test.dart
cls 9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
feat: import Chinese-localized Buzz source snapshot
Signed-off-by: cls_宁波本机 <908705107@qq.com>
2026-08-13 18:34:25 +08:00

255 lines
8.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:buzz/shared/theme/theme.dart';
void main() {
group('themePairs', () {
test('every pair member exists in the catalog', () {
for (final entry in themePairs.entries) {
expect(
findTheme(entry.key),
isNotNull,
reason: '${entry.key} is not in themeCatalog',
);
expect(
findTheme(entry.value),
isNotNull,
reason: '${entry.value} is not in themeCatalog',
);
}
});
test('pairs map a light theme to a dark one', () {
for (final entry in themePairs.entries) {
expect(
findTheme(entry.key)!.isDark,
isFalse,
reason: '${entry.key} should be light',
);
expect(
findTheme(entry.value)!.isDark,
isTrue,
reason: '${entry.value} should be dark',
);
}
});
test('resolves in both directions', () {
expect(themePairFor('github-light'), 'github-dark');
expect(themePairFor('github-dark'), 'github-light');
expect(themePairFor('andromeeda'), isNull);
expect(isPairedTheme('catppuccin-latte'), isTrue);
expect(isPairedTheme('andromeeda'), isFalse);
});
});
group('themeGroups', () {
test('light and dark partition the whole catalog', () {
final groups = themeGroups();
expect(groups.light.length + groups.dark.length, themeCatalog.length);
expect(groups.light.every((t) => !t.isDark), isTrue);
expect(groups.dark.every((t) => t.isDark), isTrue);
});
test('paired holds only light members of pairs', () {
final groups = themeGroups();
expect(groups.paired.length, themePairs.length);
for (final theme in groups.paired) {
expect(theme.isDark, isFalse);
expect(themePairs.containsKey(theme.name), isTrue);
}
});
test('groups are sorted by display name', () {
final groups = themeGroups();
for (final list in [groups.paired, groups.light, groups.dark]) {
final names = list.map((t) => t.displayName).toList();
expect(names, orderedEquals(List.of(names)..sort()));
}
});
});
group('pairedThemeLabel', () {
test('strips brightness tokens', () {
expect(pairedThemeLabel('github-light'), 'Github');
expect(pairedThemeLabel('github-light-default'), 'Github Default');
expect(pairedThemeLabel('gruvbox-light-soft'), 'Gruvbox Soft');
expect(pairedThemeLabel('material-theme-lighter'), 'Material Theme');
expect(pairedThemeLabel('catppuccin-latte'), 'Catppuccin');
});
test('falls back to the raw name when stripping empties it', () {
expect(pairedThemeLabel('light-plus'), 'Light Plus');
});
test('never produces a blank label for a real pair', () {
for (final lightName in themePairs.keys) {
expect(pairedThemeLabel(lightName), isNotEmpty);
}
});
});
group('resolveSchemes', () {
test('system mode pairs the selection across brightnesses', () {
final resolved = resolveSchemes('github-light', ThemeMode.system);
// Null forcedMode leaves MaterialApp following the OS.
expect(resolved.forcedMode, isNull);
expect(resolved.light.brightness, Brightness.light);
expect(resolved.dark.brightness, Brightness.dark);
});
test('system mode works from the dark half of a pair too', () {
final resolved = resolveSchemes('github-dark', ThemeMode.system);
expect(resolved.forcedMode, isNull);
expect(resolved.light.brightness, Brightness.light);
expect(resolved.dark.brightness, Brightness.dark);
});
test('system mode pins an unpaired theme to its own brightness', () {
final resolved = resolveSchemes('andromeeda', ThemeMode.system);
// No counterpart exists, so both sides render the selected theme rather
// than jumping to an unrelated one.
expect(resolved.forcedMode, ThemeMode.dark);
expect(resolved.light, resolved.dark);
expect(resolved.dark.brightness, Brightness.dark);
});
test('system mode pins an unpaired light theme to light mode', () {
final resolved = resolveSchemes('snazzy-light', ThemeMode.system);
expect(resolved.forcedMode, ThemeMode.light);
expect(resolved.light, resolved.dark);
expect(resolved.light.brightness, Brightness.light);
});
test('light mode forces light and swaps a dark selection for its pair', () {
final resolved = resolveSchemes('github-dark', ThemeMode.light);
expect(resolved.forcedMode, ThemeMode.light);
expect(resolved.light, resolved.dark);
expect(resolved.light.brightness, Brightness.light);
expect(resolved.light, generateColorScheme(findTheme('github-light')!));
});
test('dark mode forces dark and swaps a light selection for its pair', () {
final resolved = resolveSchemes('github-light', ThemeMode.dark);
expect(resolved.forcedMode, ThemeMode.dark);
expect(resolved.dark.brightness, Brightness.dark);
expect(resolved.dark, generateColorScheme(findTheme('github-dark')!));
});
test('dark mode falls back to the default pair when pick is unpaired', () {
// 'snazzy-light' is light and has no dark counterpart.
final resolved = resolveSchemes('snazzy-light', ThemeMode.dark);
expect(resolved.forcedMode, ThemeMode.dark);
expect(resolved.dark.brightness, Brightness.dark);
expect(resolved.darkTheme?.name, buzzDarkThemeName);
expect(resolved.dark, generateColorScheme(findTheme(buzzDarkThemeName)!));
});
test('light mode falls back to the default pair when pick is unpaired', () {
final resolved = resolveSchemes('andromeeda', ThemeMode.light);
expect(resolved.forcedMode, ThemeMode.light);
expect(resolved.light.brightness, Brightness.light);
expect(resolved.lightTheme?.name, buzzThemeName);
expect(resolved.light, generateColorScheme(findTheme(buzzThemeName)!));
});
test('an unknown scheme name falls back to the default theme', () {
final resolved = resolveSchemes('not-a-theme', ThemeMode.light);
expect(
resolved.light,
generateColorScheme(findTheme(defaultSchemeName)!),
);
});
});
group('schemeForAppearanceMode', () {
test('system mode replaces an unpaired selection with a paired theme', () {
expect(
schemeForAppearanceMode('snazzy-light', ThemeMode.system),
themeGroups().paired.first.name,
);
expect(
schemeForAppearanceMode('nord', ThemeMode.system),
themeGroups().paired.first.name,
);
});
test('system mode preserves either half of a paired selection', () {
expect(
schemeForAppearanceMode('github-light', ThemeMode.system),
'github-light',
);
expect(
schemeForAppearanceMode('github-dark', ThemeMode.system),
'github-dark',
);
});
test('pinned modes preserve an unpaired selection', () {
expect(
schemeForAppearanceMode('snazzy-light', ThemeMode.light),
'snazzy-light',
);
expect(schemeForAppearanceMode('nord', ThemeMode.dark), 'nord');
});
});
group('effectiveTheme', () {
test('system mode keeps the stored selection', () {
expect(
effectiveTheme('github-dark', ThemeMode.system)?.name,
'github-dark',
);
});
test('pinned modes report the coerced theme', () {
expect(
effectiveTheme('github-dark', ThemeMode.light)?.name,
'github-light',
);
expect(
effectiveTheme('github-light', ThemeMode.dark)?.name,
'github-dark',
);
});
test('a null selection resolves to the default theme', () {
expect(effectiveTheme(null, ThemeMode.light)?.name, defaultSchemeName);
});
});
group('themeSelectionLabel', () {
test('names the pair as a whole in system mode', () {
expect(themeSelectionLabel('github-light', ThemeMode.system), 'Github');
expect(themeSelectionLabel('github-dark', ThemeMode.system), 'Github');
});
test('names the concrete theme in pinned modes', () {
expect(
themeSelectionLabel('github-light', ThemeMode.light),
'Github Light',
);
expect(
themeSelectionLabel('github-light', ThemeMode.dark),
'Github Dark',
);
});
test('falls back to the theme display name when unpaired', () {
expect(themeSelectionLabel('andromeeda', ThemeMode.system), 'Andromeeda');
});
});
}