- Add VariableSpec class with magnitude field validation - Add Formula class supporting multiple input/output variables - Support d4rt_code as string or object with code field - Add comprehensive tests for parsing and serialization - Fix broken test import in pruebas_d4rt_test.dart Follows README.md format requirements exactly
246 lines
7 KiB
Dart
246 lines
7 KiB
Dart
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
import 'dart:convert';
|
|
|
|
import 'package:convert/convert.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
void main() {
|
|
group('encoder', () {
|
|
test("doesn't percent-encode unreserved characters", () {
|
|
var safeChars = 'abcdefghijklmnopqrstuvwxyz'
|
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
'0123456789-._~';
|
|
expect(percent.encode([...safeChars.codeUnits]), equals(safeChars));
|
|
});
|
|
|
|
test('percent-encodes reserved ASCII characters', () {
|
|
expect(percent.encode([...' `{@[,/^}\x7f\x00%'.codeUnits]),
|
|
equals('%20%60%7B%40%5B%2C%2F%5E%7D%7F%00%25'));
|
|
});
|
|
|
|
test('percent-encodes non-ASCII characters', () {
|
|
expect(percent.encode([0x80, 0xFF]), equals('%80%FF'));
|
|
});
|
|
|
|
test('mixes encoded and unencoded characters', () {
|
|
expect(percent.encode([...'a+b=\x80'.codeUnits]), equals('a%2Bb%3D%80'));
|
|
});
|
|
|
|
group('with chunked conversion', () {
|
|
test('percent-encodes byte arrays', () {
|
|
var results = <String>[];
|
|
var controller = StreamController<String>(sync: true);
|
|
controller.stream.listen(results.add);
|
|
var sink = percent.encoder.startChunkedConversion(controller.sink);
|
|
|
|
sink.add([...'a+b=\x80'.codeUnits]);
|
|
expect(results, equals(['a%2Bb%3D%80']));
|
|
|
|
sink.add([0x00, 0x01, 0xfe, 0xff]);
|
|
expect(results, equals(['a%2Bb%3D%80', '%00%01%FE%FF']));
|
|
});
|
|
|
|
test('handles empty and single-byte lists', () {
|
|
var results = <String>[];
|
|
var controller = StreamController<String>(sync: true);
|
|
controller.stream.listen(results.add);
|
|
var sink = percent.encoder.startChunkedConversion(controller.sink);
|
|
|
|
sink.add([]);
|
|
expect(results, equals(['']));
|
|
|
|
sink.add([0x00]);
|
|
expect(results, equals(['', '%00']));
|
|
|
|
sink.add([]);
|
|
expect(results, equals(['', '%00', '']));
|
|
});
|
|
});
|
|
|
|
test('rejects non-bytes', () {
|
|
expect(() => percent.encode([0x100]), throwsFormatException);
|
|
|
|
var sink =
|
|
percent.encoder.startChunkedConversion(StreamController(sync: true));
|
|
expect(() => sink.add([0x100]), throwsFormatException);
|
|
});
|
|
});
|
|
|
|
group('decoder', () {
|
|
test('converts percent-encoded strings to byte arrays', () {
|
|
expect(
|
|
percent.decode('a%2Bb%3D%801'), equals([...'a+b=\x801'.codeUnits]));
|
|
});
|
|
|
|
test('supports lowercase letters', () {
|
|
expect(percent.decode('a%2bb%3d%80'), equals([...'a+b=\x80'.codeUnits]));
|
|
});
|
|
|
|
test('supports more aggressive encoding', () {
|
|
expect(percent.decode('%61%2E%5A'), equals([...'a.Z'.codeUnits]));
|
|
});
|
|
|
|
test('supports less aggressive encoding', () {
|
|
var chars = ' `{@[,/^}\x7F\x00';
|
|
expect(percent.decode(chars), equals([...chars.codeUnits]));
|
|
});
|
|
|
|
group('with chunked conversion', () {
|
|
late List<List<int>> results;
|
|
late StringConversionSink sink;
|
|
setUp(() {
|
|
results = [];
|
|
var controller = StreamController<List<int>>(sync: true);
|
|
controller.stream.listen(results.add);
|
|
sink = percent.decoder.startChunkedConversion(controller.sink);
|
|
});
|
|
|
|
test('converts percent to byte arrays', () {
|
|
sink.add('a%2Bb%3D%801');
|
|
expect(
|
|
results,
|
|
equals([
|
|
[...'a+b=\x801'.codeUnits]
|
|
]));
|
|
|
|
sink.add('%00%01%FE%FF');
|
|
expect(
|
|
results,
|
|
equals([
|
|
[...'a+b=\x801'.codeUnits],
|
|
[0x00, 0x01, 0xfe, 0xff]
|
|
]));
|
|
});
|
|
|
|
test('supports trailing percents and digits split across chunks', () {
|
|
sink.add('ab%');
|
|
expect(
|
|
results,
|
|
equals([
|
|
[...'ab'.codeUnits]
|
|
]));
|
|
|
|
sink.add('2');
|
|
expect(
|
|
results,
|
|
equals([
|
|
[...'ab'.codeUnits]
|
|
]));
|
|
|
|
sink.add('0cd%2');
|
|
expect(
|
|
results,
|
|
equals([
|
|
[...'ab'.codeUnits],
|
|
[...' cd'.codeUnits]
|
|
]));
|
|
|
|
sink.add('0');
|
|
expect(
|
|
results,
|
|
equals([
|
|
[...'ab'.codeUnits],
|
|
[...' cd'.codeUnits],
|
|
[...' '.codeUnits]
|
|
]));
|
|
});
|
|
|
|
test('supports empty strings', () {
|
|
sink.add('');
|
|
expect(results, isEmpty);
|
|
|
|
sink.add('%');
|
|
expect(results, equals([<Never>[]]));
|
|
|
|
sink.add('');
|
|
expect(results, equals([<Never>[]]));
|
|
|
|
sink.add('2');
|
|
expect(results, equals([<Never>[]]));
|
|
|
|
sink.add('');
|
|
expect(results, equals([<Never>[]]));
|
|
|
|
sink.add('0');
|
|
expect(
|
|
results,
|
|
equals([
|
|
<Never>[],
|
|
[0x20]
|
|
]));
|
|
});
|
|
|
|
test('rejects dangling % detected in close()', () {
|
|
sink.add('ab%');
|
|
expect(
|
|
results,
|
|
equals([
|
|
[...'ab'.codeUnits]
|
|
]));
|
|
expect(() => sink.close(), throwsFormatException);
|
|
});
|
|
|
|
test('rejects dangling digit detected in close()', () {
|
|
sink.add('ab%2');
|
|
expect(
|
|
results,
|
|
equals([
|
|
[...'ab'.codeUnits]
|
|
]));
|
|
expect(() => sink.close(), throwsFormatException);
|
|
});
|
|
|
|
test('rejects danging % detected in addSlice()', () {
|
|
sink.addSlice('ab%', 0, 3, false);
|
|
expect(
|
|
results,
|
|
equals([
|
|
[...'ab'.codeUnits]
|
|
]));
|
|
|
|
expect(() => sink.addSlice('ab%', 0, 3, true), throwsFormatException);
|
|
});
|
|
|
|
test('rejects danging digit detected in addSlice()', () {
|
|
sink.addSlice('ab%2', 0, 3, false);
|
|
expect(
|
|
results,
|
|
equals([
|
|
[...'ab'.codeUnits]
|
|
]));
|
|
|
|
expect(() => sink.addSlice('ab%2', 0, 3, true), throwsFormatException);
|
|
});
|
|
});
|
|
|
|
group('rejects non-ASCII character', () {
|
|
for (var char in ['\u0141', '\u{10041}']) {
|
|
test('"$char"', () {
|
|
expect(() => percent.decode('a$char'), throwsFormatException);
|
|
expect(() => percent.decode('${char}a'), throwsFormatException);
|
|
|
|
var sink = percent.decoder
|
|
.startChunkedConversion(StreamController(sync: true));
|
|
expect(() => sink.add(char), throwsFormatException);
|
|
});
|
|
}
|
|
});
|
|
|
|
test('rejects % followed by non-hex', () {
|
|
expect(() => percent.decode('%z2'), throwsFormatException);
|
|
expect(() => percent.decode('%2z'), throwsFormatException);
|
|
});
|
|
|
|
test('rejects dangling % detected in convert()', () {
|
|
expect(() => percent.decode('ab%'), throwsFormatException);
|
|
});
|
|
|
|
test('rejects dangling digit detected in convert()', () {
|
|
expect(() => percent.decode('ab%2'), throwsFormatException);
|
|
});
|
|
});
|
|
}
|