etm-powersync-app/test/nuance_domaine_test.dart
Patrick Schurig 4d3f35d6d0 feat(énergie): les charges d'un même domaine se nuancent — et une troisième le fait seule
La V2C et la borne simulée, toutes deux en `ev`, recevaient exactement le même
violet : indiscernables dans l'empilement, et la légende répétait la même
pastille. Vu à l'écran dès qu'une seconde borne est apparue.

`EtmTokens.nuance` décline sur le RANG dans le domaine, donc une troisième borne
prend sa teinte sans qu'on déclare quoi que ce soit. Le décalage porte sur la
LUMINOSITÉ, pas sur la teinte : glisser la teinte finirait par heurter le
domaine voisin, l'éclaircir garde la famille lisible.

⚠️ La série est bornée à quatre, et c'est explicite plutôt que subi : au-delà,
l'écart ne se voit plus, et prétendre distinguer huit nuances d'un même violet
serait une promesse que l'œil ne tient pas. Le rang 3 et le rang 9 rendent la
même couleur — le signe qu'il faut alors autre chose que la couleur pour
identifier, et c'est un choix d'écran, pas un réglage de palette. Un test le
fige.

La couleur est calculée à UN endroit, partagé par le tracé et la légende : deux
sources de couleur, c'est une légende qui finit par désigner la mauvaise bande.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
2026-09-08 11:41:24 +02:00

56 lines
2.4 KiB
Dart

/// **Deux charges d'un même domaine ne peuvent pas porter la même couleur.**
///
/// Vu à l'écran le 2026-09-08 : la V2C et la borne simulée, toutes deux en `ev`, recevaient
/// exactement le même violet — indiscernables dans l'empilement, et la légende répétait la
/// même pastille. La nuance se calcule sur le RANG dans le domaine, donc une troisième
/// borne prend sa teinte sans qu'on déclare quoi que ce soit.
library;
import 'package:etm_powersync_app/theme/etm_tokens.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
const base = EtmTokens.ev;
test('le rang 0 ne touche pas à la couleur du domaine', () {
expect(EtmTokens.nuance(base, 0), base);
});
test('trois charges d\'un même domaine donnent trois couleurs DISTINCTES', () {
final c = [for (int i = 0; i < 3; i++) EtmTokens.nuance(base, i)];
expect(c.toSet(), hasLength(3),
reason: 'une troisième borne doit se distinguer sans rien déclarer');
});
test('la luminosité monte, la teinte ne bouge pas', () {
// Glisser la teinte finirait par heurter le domaine voisin ; l'éclaircir garde la
// famille lisible.
final h0 = HSLColor.fromColor(EtmTokens.nuance(base, 0));
final h2 = HSLColor.fromColor(EtmTokens.nuance(base, 2));
expect(h2.lightness, greaterThan(h0.lightness));
expect((h2.hue - h0.hue).abs(), lessThan(1.0));
});
test('la série est BORNÉE, et ne prétend pas distinguer l\'indistinguable', () {
// Au-delà de quatre, l'écart de luminosité ne se voit plus. Le plafond est explicite
// plutôt que subi : le rang 3 et le rang 9 rendent la même couleur, et c'est le signe
// qu'il faut autre chose que la couleur pour identifier — pas une nuance de plus.
expect(EtmTokens.nuance(base, 9), EtmTokens.nuance(base, 3));
});
testWidgets('un domaine inconnu n\'a pas de couleur — et pas une couleur par défaut',
(tester) async {
// Une charge sans domaine déclaré n'est pas classée : lui donner une couleur de
// domaine la ferait passer pour classée.
late BuildContext ctx;
await tester.pumpWidget(MaterialApp(home: Builder(builder: (c) {
ctx = c;
return const SizedBox();
})));
expect(EtmTokens.domaineOf(ctx, null), isNull);
expect(EtmTokens.domaineOf(ctx, 'inconnu'), isNull);
expect(EtmTokens.domaineOf(ctx, 'ev'), isNotNull);
});
}