From e3c076f1fd0f1c72e59630689c31a44323a282c1 Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 27 Nov 2025 10:30:59 +0700 Subject: [PATCH] TF-4169 Add precheck for HexColor and unit test --- labels/lib/model/hex_color.dart | 17 ++++- labels/pubspec.lock | 2 +- labels/pubspec.yaml | 2 + labels/test/method/model/hex_color_test.dart | 71 ++++++++++++++++++++ 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 labels/test/method/model/hex_color_test.dart diff --git a/labels/lib/model/hex_color.dart b/labels/lib/model/hex_color.dart index 804e9ebdb..681a0dd80 100644 --- a/labels/lib/model/hex_color.dart +++ b/labels/lib/model/hex_color.dart @@ -1,9 +1,24 @@ import 'package:equatable/equatable.dart'; +import 'package:quiver/check.dart'; class HexColor with EquatableMixin { + // Only accept #RRGGBB or #AARRGGBB format + static final RegExp _hexPattern = + RegExp(r'^#[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$'); + final String value; - HexColor(this.value); + HexColor(this.value) { + checkArgument(value.isNotEmpty, message: 'hex string must not be empty'); + checkArgument( + value.startsWith('#'), + message: 'hex string must start with #', + ); + checkArgument( + _hexPattern.hasMatch(value), + message: 'invalid hex format: expected #RRGGBB or #AARRGGBB', + ); + } @override List get props => [value]; diff --git a/labels/pubspec.lock b/labels/pubspec.lock index a2581ff21..78379177a 100644 --- a/labels/pubspec.lock +++ b/labels/pubspec.lock @@ -437,7 +437,7 @@ packages: source: hosted version: "1.4.0" quiver: - dependency: transitive + dependency: "direct main" description: name: quiver sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 diff --git a/labels/pubspec.yaml b/labels/pubspec.yaml index 7f210ad35..cd35e51b6 100644 --- a/labels/pubspec.yaml +++ b/labels/pubspec.yaml @@ -24,6 +24,8 @@ dependencies: dio: 5.0.0 + quiver: 3.2.1 + dev_dependencies: flutter_test: sdk: flutter diff --git a/labels/test/method/model/hex_color_test.dart b/labels/test/method/model/hex_color_test.dart new file mode 100644 index 000000000..7c1e0440e --- /dev/null +++ b/labels/test/method/model/hex_color_test.dart @@ -0,0 +1,71 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:labels/model/hex_color.dart'; + +void main() { + group('HexColor', () { + test('creates instance when valid #RRGGBB', () { + final color = HexColor('#A1B2C3'); + expect(color.value, '#A1B2C3'); + }); + + test('creates instance when valid #AARRGGBB', () { + final color = HexColor('#80A1B2C3'); + expect(color.value, '#80A1B2C3'); + }); + + test('throws when value is empty', () { + expect( + () => HexColor(''), + throwsA( + predicate((e) => + e is ArgumentError && + e.message == 'hex string must not be empty'), + ), + ); + }); + + test('throws when missing leading #', () { + expect( + () => HexColor('A1B2C3'), + throwsA( + predicate((e) => + e is ArgumentError && + e.message == 'hex string must start with #'), + ), + ); + }); + + test('throws when format #FFF (unsupported)', () { + expect( + () => HexColor('#FFF'), + throwsA( + predicate((e) => + e is ArgumentError && + e.message == 'invalid hex format: expected #RRGGBB or #AARRGGBB'), + ), + ); + }); + + test('throws when contains invalid characters', () { + expect( + () => HexColor('#GGHHII'), + throwsA(isA()), + ); + }); + + test('throws when length is too long', () { + expect( + () => HexColor('#A1B2C3D4E5'), + throwsA(isA()), + ); + }); + + test('supports value equality (Equatable)', () { + final c1 = HexColor('#FFFFFF'); + final c2 = HexColor('#FFFFFF'); + + expect(c1, equals(c2)); + expect(c1.props, equals(['#FFFFFF'])); + }); + }); +}