diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e6db82..19c114f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,3 +33,4 @@ - Implement `xsd:float` codec - Implement `xsd:unsignedInt` codec - Implement `xsd:integer` codec +- Implement `xsd:negativeInteger` codec diff --git a/README.md b/README.md index e353563..9c017b4 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ This library aims to support the following XSD 1.1 built-in datatypes that are c | `xsd:float` | ✅ | ✅ | `double` | `dart:core` | | `xsd:integer` | ✅ | ✅ | `BigInt` | `dart:core` | | `xsd:nonPositiveInteger` | ✅ | ✅ | `BigInt` | `dart:core` | -| `xsd:negativeInteger` | ✅ | ❌ | `BigInt` | `dart:core` | +| `xsd:negativeInteger` | ✅ | ✅ | `BigInt` | `dart:core` | | `xsd:long` | ✅ | ✅ | `BigInt` | `dart:core` | | `xsd:int` | ✅ | ✅ | `int` | `dart:core` | | `xsd:short` | ✅ | ✅ | `int` | `dart:core` | diff --git a/lib/src/codecs/codecs.dart b/lib/src/codecs/codecs.dart index 4aac7f6..65d893f 100644 --- a/lib/src/codecs/codecs.dart +++ b/lib/src/codecs/codecs.dart @@ -30,3 +30,4 @@ export 'double/double_codec.dart'; export 'float/float_codec.dart'; export 'integer/integer_codec.dart'; export 'unsigned_int/unsigned_int_codec.dart'; +export 'negative_integer/negative_integer_codec.dart'; diff --git a/lib/src/codecs/negative_integer/negative_integer_codec.dart b/lib/src/codecs/negative_integer/negative_integer_codec.dart new file mode 100644 index 0000000..55cd4e7 --- /dev/null +++ b/lib/src/codecs/negative_integer/negative_integer_codec.dart @@ -0,0 +1,18 @@ +import 'dart:convert'; + +import 'package:xsd/src/codecs/negative_integer/negative_integer_decoder.dart'; +import 'package:xsd/src/codecs/negative_integer/negative_integer_encoder.dart'; + +/// A codec for xsd:negativeInteger. +/// +/// Converts between a string representation of a negative integer and a +/// [BigInt]. +class XsdNegativeIntegerCodec extends Codec { + const XsdNegativeIntegerCodec(); + + @override + Converter get decoder => const XsdNegativeIntegerDecoder(); + + @override + Converter get encoder => const XsdNegativeIntegerEncoder(); +} diff --git a/lib/src/codecs/negative_integer/negative_integer_decoder.dart b/lib/src/codecs/negative_integer/negative_integer_decoder.dart new file mode 100644 index 0000000..7b5186e --- /dev/null +++ b/lib/src/codecs/negative_integer/negative_integer_decoder.dart @@ -0,0 +1,32 @@ +import 'dart:convert'; + +import '../../helpers/whitespace.dart'; + +class XsdNegativeIntegerDecoder extends Converter { + const XsdNegativeIntegerDecoder(); + + static final BigInt _maxValue = BigInt.from(-1); + + @override + BigInt convert(String input) { + final str = processWhiteSpace(input, Whitespace.collapse); + + if (str.isEmpty) { + throw const FormatException('The input string cannot be empty.'); + } + + final value = BigInt.tryParse(str); + + if (value == null) { + throw FormatException('The input "$str" is not a valid integer.'); + } + + if (value > _maxValue) { + throw FormatException( + 'The value "$value" must be less than or equal to $_maxValue.', + ); + } + + return value; + } +} diff --git a/lib/src/codecs/negative_integer/negative_integer_encoder.dart b/lib/src/codecs/negative_integer/negative_integer_encoder.dart new file mode 100644 index 0000000..ba682d8 --- /dev/null +++ b/lib/src/codecs/negative_integer/negative_integer_encoder.dart @@ -0,0 +1,18 @@ +import 'dart:convert'; + +class XsdNegativeIntegerEncoder extends Converter { + const XsdNegativeIntegerEncoder(); + + static final BigInt _maxValue = BigInt.from(-1); + + @override + String convert(BigInt input) { + if (input > _maxValue) { + throw FormatException( + 'The value "$input" must be less than or equal to $_maxValue.', + ); + } + + return input.toString(); + } +} diff --git a/test/codecs/negative_integer_codec_test.dart b/test/codecs/negative_integer_codec_test.dart new file mode 100644 index 0000000..ba9abd9 --- /dev/null +++ b/test/codecs/negative_integer_codec_test.dart @@ -0,0 +1,29 @@ +import 'package:test/test.dart'; +import 'package:xsd/xsd.dart'; + +void main() { + group('XsdNegativeIntegerCodec', () { + const codec = XsdNegativeIntegerCodec(); + + test('should encode valid negative integer', () { + expect(codec.encode(BigInt.from(-1)), '-1'); + expect(codec.encode(BigInt.from(-123)), '-123'); + }); + + test('should decode valid negative integer', () { + expect(codec.decode('-1'), BigInt.from(-1)); + expect(codec.decode('-123'), BigInt.from(-123)); + expect(codec.decode(' -123 '), BigInt.from(-123)); + }); + + test('should throw on invalid negative integer', () { + expect(() => codec.decode('0'), throwsFormatException); + expect(() => codec.decode('1'), throwsFormatException); + expect(() => codec.decode('abc'), throwsFormatException); + expect(() => codec.decode(''), throwsFormatException); + expect(() => codec.decode(' '), throwsFormatException); + expect(() => codec.encode(BigInt.zero), throwsFormatException); + expect(() => codec.encode(BigInt.one), throwsFormatException); + }); + }); +}