refactor: enhance parseFixed logic with tryParseFixed support and improve error handling in edge cases, including unit tests (#2682)

This commit is contained in:
Konstantin Ullrich
2025-11-26 14:55:01 +01:00
committed by GitHub
parent ac1497bd3d
commit 6b725cceeb
2 changed files with 90 additions and 3 deletions
+31 -3
View File
@@ -1,23 +1,51 @@
/// Parses the string [value] as a fixed-point decimal literal and returns its
/// [BigInt] value.
///
/// The number of fractional digits is determined by [decimals].
///
/// Returns `null` if the input [value] is not a valid fixed-point literal
/// (e.g., non-numeric characters, too many fractional digits).
///
/// Like [parseFixed], except that this function returns `null` for invalid inputs
/// instead of throwing.
BigInt? tryParseFixed(String value, int decimals) {
try {
return parseFixed(value, decimals);
} on FormatException catch (_) {
return null;
}
}
/// Parses the string [value] as a fixed-point decimal literal and returns its
/// [BigInt] value.
///
/// The number of fractional digits is determined by [decimals].
///
/// Throws a [FormatException] if the input [value] is not a valid fixed-point literal
/// (e.g., non-numeric characters, too many fractional digits).
///
/// Rather than throwing and immediately catching the [FormatException],
/// instead use [tryParseFixed] to handle a potential parsing error.
BigInt parseFixed(String value, int decimals) {
final multiplier = getMultiplier(decimals);
final negative = value.startsWith("-");
if (negative) value = value.substring(1);
if (value == ".") throw Exception("missing value, value, $value");
if (value == ".") throw FormatException("missing value, value, $value");
if (value.startsWith(".")) value = "0$value";
final comps = value.split(".");
if (comps.length > 2) {
throw Exception("too many decimal points, value, $value");
throw FormatException("too many decimal points, value, $value");
}
var whole = comps.isNotEmpty ? comps[0] : "0";
var fraction = (comps.length == 2 ? comps[1] : "0").padRight(decimals, "0");
if (fraction.length > multiplier.length - 1) {
throw Exception(
throw FormatException(
"fractional component exceeds decimals, underflow, parseFixed");
}
+59
View File
@@ -34,5 +34,64 @@ void main() {
test('should parse -.00002 as -20', () => expect(parseFixed("-.00002", 6), BigInt.from(-20)));
});
group('parseFixed, failing', () {
test('should fail to parse .000.0010, too many fractional digits',
() => expect(() => parseFixed(".000.0010", 6), throwsFormatException));
test('should fail to parse .0000010, fractional component exceeds decimals',
() => expect(() => parseFixed(".0000010", 6), throwsFormatException));
test('should fail to parse `.`, missing value',
() => expect(() => parseFixed(".", 6), throwsFormatException));
});
});
group('tryParseFixed', () {
group('tryParseFixed, positive', () {
test('should parse 1.000001 as 1000001',
() => expect(tryParseFixed("1.000001", 6), BigInt.from(1000001)));
test('should parse 1 as 1000000', () => expect(tryParseFixed("1", 6), BigInt.from(1000000)));
test(
'should parse 1. as 1000000', () => expect(tryParseFixed("1.", 6), BigInt.from(1000000)));
test('should parse 1.1 as 1100000',
() => expect(tryParseFixed("1.1", 6), BigInt.from(1100000)));
test('should parse 01.1 as 1100000',
() => expect(tryParseFixed("01.1", 6), BigInt.from(1100000)));
test('should parse 1100000 as 11000000',
() => expect(tryParseFixed("1100000", 1), BigInt.from(11000000)));
});
group('tryParseFixed, negative', () {
test('should parse -1.000001 as -1000001',
() => expect(tryParseFixed("-1.000001", 6), BigInt.from(-1000001)));
test('should parse -1 as 1000000',
() => expect(tryParseFixed("-1", 6), BigInt.from(-1000000)));
});
group('tryParseFixed, no leading 0', () {
test('should parse .000001 as 1', () => expect(tryParseFixed(".000001", 6), BigInt.from(1)));
test('should parse .00002 as 20', () => expect(tryParseFixed(".00002", 6), BigInt.from(20)));
test('should parse -.00002 as -20',
() => expect(tryParseFixed("-.00002", 6), BigInt.from(-20)));
});
group('tryParseFixed, return `null`', () {
test('should parse .000.0010 as null, too many fractional digits',
() => expect(tryParseFixed(".000.0010", 6), isNull));
test('should parse .0000010 as null, fractional component exceeds decimals',
() => expect(tryParseFixed(".0000010", 6), isNull));
test('should parse . as `null`, missing value', () => expect(tryParseFixed(".", 6), isNull));
});
});
}