New test case and fixes

This commit is contained in:
Tony Garnock-Jones 2024-03-27 10:57:19 +01:00
parent f0815ce4eb
commit 0aa39da971
8 changed files with 30 additions and 5 deletions

View File

@ -8,7 +8,8 @@ import { Bytes, BytesLike, underlying, hexDigit } from "./bytes";
import { Value } from "./values";
import { is } from "./is";
import { GenericEmbedded, Embeddable, EmbeddedTypeDecode } from "./embedded";
import { ReaderStateOptions } from "reader";
import { ReaderStateOptions } from "./reader";
import { stringify } from "./text";
export interface DecoderOptions {
includeAnnotations?: boolean;
@ -221,6 +222,7 @@ export class Decoder<T extends Embeddable = never> implements TypedDecoder<T> {
const d = new Dictionary<T>();
if (vs.length % 2) throw new DecodeError("Missing dictionary value");
for (let i = 0; i < vs.length; i += 2) {
if (d.has(vs[i])) throw new DecodeError(`Duplicate key: ${stringify(vs[i])}`);
d.set(vs[i], vs[i+1]);
}
return d;
@ -253,7 +255,12 @@ export class Decoder<T extends Embeddable = never> implements TypedDecoder<T> {
return this.state.wrap<T>(Record(vs[0], vs.slice(1)));
}
case Tag.Sequence: return this.state.wrap<T>(this.nextvalues());
case Tag.Set: return this.state.wrap<T>(new Set(this.nextvalues()));
case Tag.Set: {
const vs = this.nextvalues();
const s = new Set<T>(vs);
if (vs.length !== s.size) throw new DecodeError("Duplicate value in set");
return this.state.wrap<T>(s);
}
case Tag.Dictionary: return this.state.wrap<T>(Decoder.dictionaryFromArray(this.nextvalues()));
default: throw new DecodeError("Unsupported Preserves tag: " + tag);
}

View File

@ -217,7 +217,11 @@ class Decoder(BinaryCodec):
if not vs: raise DecodeError('Too few elements in encoded record')
return self.wrap(Record(vs[0], vs[1:]))
if tag == 0xb5: return self.wrap(tuple(self.nextvalues()))
if tag == 0xb6: return self.wrap(frozenset(self.nextvalues()))
if tag == 0xb6:
vs = self.nextvalues()
s = frozenset(vs)
if len(s) != len(vs): raise DecodeError('Duplicate value')
return self.wrap(s)
if tag == 0xb7: return self.wrap(ImmutableDict.from_kvs(self.nextvalues()))
raise DecodeError('Invalid tag: ' + hex(tag))

View File

@ -92,6 +92,7 @@
dict2: @"Missing close brace" <ParseShort "{ a: b, c: d ">
dict2a: @"Missing close brace" <ParseShort "{">
dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }">
dict3a: @"Duplicate key" <DecodeError #x"b7 b00101 b00102 b00101 b00103 84">
dict4: @"Unexpected close brace" <ParseError "}">
dict5: @"Missing value" <DecodeError #x"b7 b00101 b00102 b00103 84">
dict6: @"Comma not allowed between key and colon" <ParseError "{ a,: 1, b: 2 }">
@ -191,6 +192,7 @@
set2: @"Missing close brace" <ParseShort "#{ 1 2 3 ">
set2a: @"Missing close brace" <ParseShort "#{">
set3: @"Duplicate value" <ParseError "#{a a}">
set3a: @"Duplicate value" <DecodeError #x"b6 b00101 b00101 84">
string0: <Test #x"b100" "">
string3: <Test #x"b10568656c6c6f" "hello">
string4: <Test #x"b1 14 616263e6b0b4e6b0b45c2f22080c0a0d0978797a" "abc\u6c34\u6C34\\/\"\b\f\n\r\txyz">

View File

@ -83,7 +83,7 @@
[#xB3 (string->symbol (bytes->string/utf-8 (next-bytes (next-varint))))]
[#xB4 (apply (lambda (label . fields) (record label fields)) (next-items))]
[#xB5 (next-items)]
[#xB6 (list->set (next-items))]
[#xB6 (build-set (next-items))]
[#xB7 (build-dictionary (next-items))]
[_ (return (on-fail "Invalid Preserves binary tag: ~v" lead-byte))]))
@ -112,9 +112,17 @@
['#:end '()]
[v (cons (wrap pos0 v) (next-items))]))
(define (build-set items)
(define s (list->set items))
(unless (= (set-count s) (length items)) (return (on-fail "Duplicate value in set")))
s)
(define (build-dictionary items)
(when (not (even? (length items))) (return (on-fail "Odd number of items in dictionary")))
(apply hash items))
(define h (apply hash items))
(unless (= (hash-count h) (quotient (length items) 2))
(return (on-fail "Duplicate key in dictionary")))
h)
(let ((pos0 (pos)))
(match (read-byte in-port)

View File

@ -92,6 +92,7 @@
dict2: @"Missing close brace" <ParseShort "{ a: b, c: d ">
dict2a: @"Missing close brace" <ParseShort "{">
dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }">
dict3a: @"Duplicate key" <DecodeError #x"b7 b00101 b00102 b00101 b00103 84">
dict4: @"Unexpected close brace" <ParseError "}">
dict5: @"Missing value" <DecodeError #x"b7 b00101 b00102 b00103 84">
dict6: @"Comma not allowed between key and colon" <ParseError "{ a,: 1, b: 2 }">
@ -191,6 +192,7 @@
set2: @"Missing close brace" <ParseShort "#{ 1 2 3 ">
set2a: @"Missing close brace" <ParseShort "#{">
set3: @"Duplicate value" <ParseError "#{a a}">
set3a: @"Duplicate value" <DecodeError #x"b6 b00101 b00101 84">
string0: <Test #x"b100" "">
string3: <Test #x"b10568656c6c6f" "hello">
string4: <Test #x"b1 14 616263e6b0b4e6b0b45c2f22080c0a0d0978797a" "abc\u6c34\u6C34\\/\"\b\f\n\r\txyz">

Binary file not shown.

View File

@ -92,6 +92,7 @@
dict2: @"Missing close brace" <ParseShort "{ a: b, c: d ">
dict2a: @"Missing close brace" <ParseShort "{">
dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }">
dict3a: @"Duplicate key" <DecodeError #x"b7 b00101 b00102 b00101 b00103 84">
dict4: @"Unexpected close brace" <ParseError "}">
dict5: @"Missing value" <DecodeError #x"b7 b00101 b00102 b00103 84">
dict6: @"Comma not allowed between key and colon" <ParseError "{ a,: 1, b: 2 }">
@ -191,6 +192,7 @@
set2: @"Missing close brace" <ParseShort "#{ 1 2 3 ">
set2a: @"Missing close brace" <ParseShort "#{">
set3: @"Duplicate value" <ParseError "#{a a}">
set3a: @"Duplicate value" <DecodeError #x"b6 b00101 b00101 84">
string0: <Test #x"b100" "">
string3: <Test #x"b10568656c6c6f" "hello">
string4: <Test #x"b1 14 616263e6b0b4e6b0b45c2f22080c0a0d0978797a" "abc\u6c34\u6C34\\/\"\b\f\n\r\txyz">