From: Anton Rudenko Date: Fri, 31 Jan 2025 07:51:13 +0000 (+0300) Subject: Tests fixes, refactoring, additions X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=df7189a3585db5ef61651236c926447c0daa80f1860824908395f408fc9b0d46;p=keks.git Tests fixes, refactoring, additions --- diff --git a/go/atom-decode.go b/go/atom-decode.go index 0cbcc53..6129fec 100644 --- a/go/atom-decode.go +++ b/go/atom-decode.go @@ -35,8 +35,8 @@ var ( ErrBadUTF8 = errors.New("invalid UTF-8") ErrBadInt = errors.New("bad int value") ErrBadMagic = errors.New("bad magic value") - ErrTaiReserved = errors.New("reserved TAI64 values in use") - ErrTaiNonMinimal = errors.New("non-minimal TAI64") + ErrTAIReserved = errors.New("reserved TAI64 values in use") + ErrTAINonMinimal = errors.New("non-minimal TAI64") ErrTooManyNsecs = errors.New("too many nanoseconds") ErrTooManyAsecs = errors.New("too many attoseconds") ) @@ -212,13 +212,13 @@ func (ctx *Decoder) DecodeAtom() (t types.Type, err error) { return } if be.Get([]byte(s)[:8]) > (1 << 63) { - err = ErrTaiReserved + err = ErrTAIReserved return } if l > 8 { nsecs := be.Get([]byte(s)[8 : 8+4]) if l == 12 && nsecs == 0 { - err = ErrTaiNonMinimal + err = ErrTAINonMinimal return } if nsecs > 999999999 { @@ -229,7 +229,7 @@ func (ctx *Decoder) DecodeAtom() (t types.Type, err error) { if l > 12 { asecs := be.Get([]byte(s)[8+4 : 8+4+4]) if asecs == 0 { - err = ErrTaiNonMinimal + err = ErrTAINonMinimal return } if asecs > 999999999 { diff --git a/go/atom-encode.go b/go/atom-encode.go index 88d818c..25a0139 100644 --- a/go/atom-encode.go +++ b/go/atom-encode.go @@ -129,6 +129,9 @@ func BigIntEncode(w io.Writer, v *big.Int) (written int64, err error) { // Write an encoded BLOB atom. func BlobEncode(w io.Writer, chunkLen int64, r io.Reader) (written int64, err error) { + if chunkLen == 0 { + return 0, errors.New("zero chunkLen specified") + } { l := make([]byte, 9) l[0] = byte(AtomBLOB) diff --git a/go/bin_test.go b/go/bin_test.go index 31a455f..e04a6ea 100644 --- a/go/bin_test.go +++ b/go/bin_test.go @@ -1,5 +1,6 @@ // GoKEKS -- Go KEKS codec implementation // Copyright (C) 2024-2025 Anton Rudenko +// Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as @@ -17,206 +18,261 @@ package keks import ( "bytes" - "encoding/hex" "io" - "reflect" "strings" "testing" "testing/quick" + + "go.cypherpunks.su/keks/be" ) -func TestBinaryEmpty(t *testing.T) { - object := []byte{} - binstring := mustHexDec("80") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBinEmpty(t *testing.T) { + obj := []byte{} + bin := mustHexDec("80") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + t.Fatal(err) } - if err != nil { - t.Fatalf("error during decode: %s", err) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - udecoded, ok := decoded.([]byte) + casted, ok := decoded.([]byte) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") + } + if !bytes.Equal(casted, obj) { + t.Fatal("casted differs") } - if !bytes.Equal(udecoded, object) { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(decoded), decoded) - t.FailNow() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestBinary1234(t *testing.T) { - object := []byte{0x01, 0x02, 0x03, 0x04} - binstring := mustHexDec("8401020304") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBin1234(t *testing.T) { + obj := []byte{0x01, 0x02, 0x03, 0x04} + bin := mustHexDec("8401020304") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + t.Fatal(err) } - if err != nil { - t.Fatalf("error during decode: %s", err) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - udecoded, ok := decoded.([]byte) + casted, ok := decoded.([]byte) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") + } + if !bytes.Equal(casted, obj) { + t.Fatal("casted differs") } - if !bytes.Equal(udecoded, object) { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(udecoded), udecoded) - t.FailNow() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestBinaryLen62(t *testing.T) { - object := bytes.Repeat([]byte{'a'}, 62) - binstring := mustHexDec("BD01" + strings.Repeat("61", 62)) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBinLen62(t *testing.T) { + obj := bytes.Repeat([]byte{'a'}, 62) + bin := mustHexDec("BD01" + strings.Repeat("61", 62)) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + t.Fatal(err) } - if err != nil { - t.Fatalf("error during decode: %s", err) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - udecoded, ok := decoded.([]byte) + casted, ok := decoded.([]byte) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") } - if !bytes.Equal(udecoded, object) { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(udecoded), udecoded) - t.FailNow() + if !bytes.Equal(casted, obj) { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestBinaryLen318(t *testing.T) { - object := bytes.Repeat([]byte{'a'}, 318) - binstring := mustHexDec("BE0001" + strings.Repeat("61", 318)) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBinLen318(t *testing.T) { + obj := bytes.Repeat([]byte{'a'}, 62+255+1) + bin := mustHexDec("BE0001" + strings.Repeat("61", 62+255+1)) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + t.Fatal(err) } - if err != nil { - t.Fatalf("error during decode: %s", err) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - udecoded, ok := decoded.([]byte) + casted, ok := decoded.([]byte) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") + } + if !bytes.Equal(casted, obj) { + t.Fatal("casted differs") } - if !bytes.Equal(udecoded, object) { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(udecoded), udecoded) - t.FailNow() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestBinaryLen65853(t *testing.T) { - object := bytes.Repeat([]byte{'a'}, 65853) - binstring := mustHexDec("BF0000000000000000" + strings.Repeat("61", 65853)) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBinLen65853(t *testing.T) { + obj := bytes.Repeat([]byte{'a'}, 62+255+65535+1) + bin := mustHexDec("BF0000000000000000" + strings.Repeat("61", 62+255+65535+1)) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + t.Fatal(err) } - if err != nil { - t.Fatalf("error during decode: %s", err) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - udecoded, ok := decoded.([]byte) + casted, ok := decoded.([]byte) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") + } + if !bytes.Equal(casted, obj) { + t.Fatal("casted differs") } - if !bytes.Equal(udecoded, object) { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(udecoded), udecoded) - t.FailNow() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestBinaryThrowsWhenNotEnoughData(t *testing.T) { - binstring := mustHexDec("84010203") - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBinNotEnoughData(t *testing.T) { + bin := mustHexDec("84010203") + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %v", err) + t.Fatal() } } -func TestBinaryThrowsWhenNotEnoughDataForLength8(t *testing.T) { - binstring := mustHexDec("BD01" + strings.Repeat("61", 61)) - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBinNotEnoughDataForLength8(t *testing.T) { + bin := mustHexDec("BD01" + strings.Repeat("61", 61)) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %v", err) + t.Fatal() } } -func TestBinaryThrowsWhenNotEnoughDataForLength16(t *testing.T) { - binstring := mustHexDec("BE0001" + strings.Repeat("61", 317)) - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBinNotEnoughDataForLength16(t *testing.T) { + bin := mustHexDec("BE0001" + strings.Repeat("61", 317)) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %v", err) + t.Fatal() } } -func TestBinaryThrowsWhenNotEnoughDataForLength64(t *testing.T) { - binstring := mustHexDec("BF0000000000000000" + strings.Repeat("61", 65852)) - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBinNotEnoughDataForLength64(t *testing.T) { + bin := mustHexDec("BF0000000000000000" + strings.Repeat("61", 65852)) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %v", err) + t.Fatal() + } +} + +func TestBinTooLong(t *testing.T) { + bin := make([]byte, 9) + bin[0] = 0xBF + for _, l := range []uint64{ + 1 << 63, + (1 << 63) - 63, + (1 << 63) - 63 - ((1 << 8) - 1), + (1 << 63) - 63 - ((1 << 8) - 1) - ((1 << 16) - 1) + 1, + } { + be.Put(bin[1:], l) + decoder := NewDecoderFromBytes(bin, nil) + _, err := decoder.Decode() + if err != ErrLenTooBig { + t.Fatal(err) + } } } -func TestBinarySymmetric(t *testing.T) { - f := func(object []byte) bool { - encoded, err := EncodeBuf(object, nil) +func TestBinNotTooLong(t *testing.T) { + bin := make([]byte, 9) + bin[0] = 0xBF + be.Put(bin[1:], (1<<63)-63-((1<<8)-1)-((1<<16)-1)) + decoder := NewDecoderFromReader(bytes.NewReader(bin), nil) + defer func() { recover() }() + _, err := decoder.Decode() + // it won't reach that code because it can not allocate so much + // memory in .getBytes(), but that means, that no error was returned + t.Fatal(err) +} + +func TestBinMaxStrLen(t *testing.T) { + f := func(bin []byte) bool { + if len(bin) == 0 { + return true + } + encoded, err := EncodeBuf(bin, nil) + if err != nil { + panic(err) + } + decoder := NewDecoderFromBytes(encoded, + &DecodeOpts{MaxStrLen: int64(len(bin) + 1)}) + _, err = decoder.Decode() if err != nil { return false } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder = NewDecoderFromBytes(encoded, + &DecodeOpts{MaxStrLen: int64(len(bin))}) + _, err = decoder.Decode() if err != nil { return false } - udecoded, ok := decoded.([]byte) - if !ok { - t.Fatalf("failed to cast") + if len(bin) == 1 { + return true } - if !bytes.Equal(object, udecoded) { - t.Logf("Expected <%s, %d>", reflect.TypeOf(object), object) - t.Logf("Instead <%s, %d>", reflect.TypeOf(udecoded), udecoded) + decoder = NewDecoderFromBytes(encoded, + &DecodeOpts{MaxStrLen: int64(len(bin) - 1)}) + _, err = decoder.Decode() + return err != nil + } + if err := quick.Check(f, nil); err != nil { + t.Fatal(err) + } +} + +func TestBinSymmetric(t *testing.T) { + f := func(bin []byte) bool { + encoded, err := EncodeBuf(bin, nil) + if err != nil { + panic(err) + } + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() + if err != nil { + return false + } + casted, ok := decoded.([]byte) + if !ok { return false } - return true + return bytes.Equal(bin, casted) } if err := quick.Check(f, nil); err != nil { t.Fatal(err) diff --git a/go/blob_test.go b/go/blob_test.go index a3422b0..a97d5cb 100644 --- a/go/blob_test.go +++ b/go/blob_test.go @@ -1,5 +1,6 @@ // GoKEKS -- Go KEKS codec implementation // Copyright (C) 2024-2025 Anton Rudenko +// Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as @@ -17,147 +18,218 @@ package keks import ( "bytes" - "encoding/hex" "io" - "reflect" "testing" "testing/quick" + + "go.cypherpunks.su/keks/be" ) func TestBlobMultipleOfChunkLen(t *testing.T) { - object := BlobChunked{ - Chunks: []string{"test", "data"}, + bin := bytes.Join([][]byte{ + mustHexDec("0B0000000000000003"), + {0x84}, + []byte("test"), + {0x84}, + []byte("data"), + {0x80}, + }, nil) + data := []byte("test" + "data") + encoded, err := EncodeBuf(BlobReader{ ChunkLen: 4, - } - binstring := mustHexDec("0B00000000000000038474657374846461746180") - encoded, err := EncodeBuf(object, nil) + R: bytes.NewReader(data), + }, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - udecoded, ok := decoded.(BlobChunked) + casted, ok := decoded.(BlobChunked) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") } - if object.ChunkLen != udecoded.ChunkLen { - t.Fatalf("expected <%s, %v>", reflect.TypeOf(object), object) - t.Fatalf("instead <%s, %v>", reflect.TypeOf(decoded), decoded) + if casted.Len() != 2*4 { + t.Fatal("Len() differs") } - for i := range len(object.Chunks) { - if object.Chunks[i] != udecoded.Chunks[i] { - t.Fatalf("expected <%s, %v>", reflect.TypeOf(object), object) - t.Fatalf("instead <%s, %v>", reflect.TypeOf(decoded), decoded) - } + if casted.ChunkLen != 4 { + t.Fatal("ChunkLen differs") + } + if len(casted.Chunks) != 2 { + t.Fatal("len(Chunks) differs") + } + if casted.Chunks[0] != "test" { + t.Fatal("Chunks[0] differs") + } + if casted.Chunks[1] != "data" { + t.Fatal("Chunks[1] differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } + got, err := io.ReadAll(casted.Reader()) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, data) { + t.Fatal("reader differs") } } func TestBlobLargerOfChunkLen(t *testing.T) { - object := BlobChunked{ - Chunks: []string{"test", "data", "2"}, + bin := bytes.Join([][]byte{ + mustHexDec("0B0000000000000003"), + {0x84}, + []byte("test"), + {0x84}, + []byte("data"), + {0x81}, + []byte("2"), + }, nil) + data := []byte("test" + "data" + "2") + encoded, err := EncodeBuf(BlobReader{ ChunkLen: 4, - } - binstring := mustHexDec("0B0000000000000003847465737484646174618132") - encoded, err := EncodeBuf(object, nil) + R: bytes.NewReader(data), + }, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - udecoded, ok := decoded.(BlobChunked) + casted, ok := decoded.(BlobChunked) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") } - if object.ChunkLen != udecoded.ChunkLen { - t.Fatalf("expected <%s, %v>", reflect.TypeOf(object), object) - t.Fatalf("instead <%s, %v>", reflect.TypeOf(decoded), decoded) + if casted.Len() != 2*4+1 { + t.Fatal("Len() differs") } - for i := range len(object.Chunks) { - if object.Chunks[i] != udecoded.Chunks[i] { - t.Fatalf("expected <%s, %v>", reflect.TypeOf(object), object) - t.Fatalf("instead <%s, %v>", reflect.TypeOf(decoded), decoded) - } + if casted.ChunkLen != 4 { + t.Fatal("ChunkLen differs") + } + if len(casted.Chunks) != 3 { + t.Fatal("len(Chunks) differs") + } + if casted.Chunks[0] != "test" { + t.Fatal("Chunks[0] differs") + } + if casted.Chunks[1] != "data" { + t.Fatal("Chunks[1] differs") + } + if casted.Chunks[2] != "2" { + t.Fatal("Chunks[2] differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } + got, err := io.ReadAll(casted.Reader()) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, data) { + t.Fatal("reader differs") } } func TestBlobEmpty(t *testing.T) { - object := BlobChunked{ - Chunks: []string{}, + bin := mustHexDec("0B0000000000000003" + "80") + encoded, err := EncodeBuf(BlobReader{ ChunkLen: 4, - } - binstring := mustHexDec("0B000000000000000380") - encoded, err := EncodeBuf(object, nil) + R: bytes.NewReader(nil), + }, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - udecoded, ok := decoded.(BlobChunked) + casted, ok := decoded.(BlobChunked) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") } - if object.ChunkLen != udecoded.ChunkLen { - t.Fatalf("expected <%s, %v>", reflect.TypeOf(object), object) - t.Fatalf("instead <%s, %v>", reflect.TypeOf(decoded), decoded) + if casted.Len() != 0 { + t.Fatal("Len() differs") } - for i := range len(object.Chunks) { - if object.Chunks[i] != udecoded.Chunks[i] { - t.Fatalf("expected <%s, %v>", reflect.TypeOf(object), object) - t.Fatalf("instead <%s, %v>", reflect.TypeOf(decoded), decoded) - } + if casted.ChunkLen != 4 { + t.Fatal("ChunkLen differs") + } + if len(casted.Chunks) != 0 { + t.Fatal("len(Chunks) differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } + got, err := io.ReadAll(casted.Reader()) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, []byte{}) { + t.Fatal("reader differs") } } func TestBlobSymmetric(t *testing.T) { - f := func(data []byte, ChunkLen uint8) bool { - object := BlobReader{ChunkLen: int64(ChunkLen), R: bytes.NewReader(data)} - encoded, err := EncodeBuf(object, nil) + var err error + f := func(chunkLen, chunksN uint8) bool { + if chunkLen == 0 { + chunkLen++ + } + chunks := make([][]byte, 0, chunksN) + mr := make([]io.Reader, 0, chunksN) + for range chunksN { + chunk := make([]byte, chunkLen) + if _, err = io.ReadFull(PRNG, chunk); err != nil { + panic(err) + } + chunks = append(chunks, chunk) + mr = append(mr, bytes.NewReader(chunk)) + } + encoded, err := EncodeBuf(BlobReader{ + ChunkLen: int64(chunkLen), + R: io.MultiReader(mr...), + }, nil) if err != nil { - t.Fatalf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) - return false + t.Fatal(err) + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - udecoded, ok := decoded.(BlobChunked) + casted, ok := decoded.(BlobChunked) if !ok { - t.Fatalf("failed to cast") - return false + t.Fatal("failed to cast") } - if object.ChunkLen != udecoded.ChunkLen { - t.Fatalf("expected <%s, %v>", reflect.TypeOf(object), object) - t.Fatalf("instead <%s, %v>", reflect.TypeOf(decoded), decoded) - return false + if casted.Len() != int64(chunkLen)*int64(chunksN) { + t.Fatal("Len() differs") } - for i := range len(data) { - if data[i] != udecoded.Chunks[i/int(ChunkLen)][i%int(ChunkLen)] { - t.Fatalf("expected <%s, %v>", reflect.TypeOf(object), object) - t.Fatalf("instead <%s, %v>", reflect.TypeOf(decoded), decoded) - return false - } + if casted.ChunkLen != int64(chunkLen) { + t.Fatal("ChunkLen differs") } - for i := range int(ChunkLen)*(len(data)/int(ChunkLen)) - len(data) { - if udecoded.Chunks[len(data)/int(ChunkLen)][i] != 0 { - t.Fatalf("expected <%s, %v>", reflect.TypeOf(object), object) - t.Fatalf("instead <%s, %v>", reflect.TypeOf(decoded), decoded) - return false + if len(casted.Chunks) != int(chunksN) { + t.Fatal("len(Chunks) differs") + } + for i := range len(chunks) { + if casted.Chunks[i] != string(chunks[i]) { + t.Fatal("chunk differs") } } return true @@ -167,34 +239,66 @@ func TestBlobSymmetric(t *testing.T) { } } -func TestBlobThrowsWhenNotEnoughData(t *testing.T) { - binstring := mustHexDec("0B00000000000000038474657374846461") - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBlobNotEnoughData(t *testing.T) { + bin := bytes.Join([][]byte{ + mustHexDec("0B0000000000000003"), + {0x84}, + []byte("test"), + {0x84}, + []byte("da"), + }, nil) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %s", err) + t.Fatal(err) + } +} + +func TestBlobTooLong(t *testing.T) { + bin := make([]byte, 1+8) + bin[0] = byte(AtomBLOB) + be.Put(bin[1:], (1<<63)-1) + _, err := NewDecoderFromBytes(bin, nil).Decode() + if err != ErrLenTooBig { + t.Fatal(err) } } -func TestBlobThrowsWhenNotEnoughDataForLength(t *testing.T) { - binstring := mustHexDec("0B00000000") - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBlobNotEnoughDataForLength(t *testing.T) { + bin := mustHexDec("0B00000000") + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %s", err) + t.Fatal(err) } } -func TestBlobThrowsWhenWrongTerminatorLength(t *testing.T) { - binstring := mustHexDec("0B0000000000000003847465737484646174618A7465726D696E61746F72") - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBlobWrongTerminatorLength(t *testing.T) { + bin := bytes.Join([][]byte{ + mustHexDec("0B0000000000000003"), + {0x84}, + []byte("test"), + {0x84}, + []byte("data"), + {0x8A}, + []byte("terminator"), + }, nil) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != ErrBlobBadChunkLen { - t.Fatalf("expected ErrBlobBadChunkLen, got %s", err) + t.Fatal(err) } } -func TestBlobThrowsWhenWrongTerminatorTag(t *testing.T) { - binstring := mustHexDec("0B00000000000000038474657374846461746104746861742077617320612077726F6E6720746167") - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBlobWrongTerminatorTag(t *testing.T) { + bin := bytes.Join([][]byte{ + mustHexDec("0B0000000000000003"), + {0x84}, + []byte("test"), + {0x84}, + []byte("data"), + {0x04}, + []byte("that was a wrong tag"), + }, nil) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != ErrBlobBadAtom { - t.Fatalf("expected ErrBlobBadChunkLen, got %s", err) + t.Fatal(err) } } diff --git a/go/bool_test.go b/go/bool_test.go index eaed601..c5c1a02 100644 --- a/go/bool_test.go +++ b/go/bool_test.go @@ -1,5 +1,6 @@ // GoKEKS -- Go KEKS codec implementation // Copyright (C) 2024-2025 Anton Rudenko +// Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as @@ -17,49 +18,57 @@ package keks import ( "bytes" - "encoding/hex" - "reflect" "testing" ) -func TestTrue(t *testing.T) { - object := true - binstring := mustHexDec("03") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBoolTrue(t *testing.T) { + bin := mustHexDec("03") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(true, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - if decoded != object { - t.Logf("expected type %s, value true", reflect.TypeOf(object)) - t.Logf("got type %s, value %t", reflect.TypeOf(decoded), decoded) - t.FailNow() + casted, ok := decoded.(bool) + if !ok { + t.Fatal("failed to cast") + } + if !casted { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestFalse(t *testing.T) { - object := false - binstring := mustHexDec("02") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestBoolFalse(t *testing.T) { + bin := mustHexDec("02") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(false, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) + } + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") + } + casted, ok := decoded.(bool) + if !ok { + t.Fatal("failed to cast") } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if casted { + t.Fatal("casted differs") } - if decoded != object { - t.Logf("expected type %s, value false", reflect.TypeOf(object)) - t.Logf("got type %s, value %+v", reflect.TypeOf(decoded), decoded) - t.FailNow() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } diff --git a/go/float_test.go b/go/float_test.go index 5c06602..8e32f82 100644 --- a/go/float_test.go +++ b/go/float_test.go @@ -1,5 +1,6 @@ // GoKEKS -- Go KEKS codec implementation // Copyright (C) 2024-2025 Anton Rudenko +// Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as @@ -18,123 +19,147 @@ package keks import ( "bytes" "io" - "reflect" "testing" ) -func TestThrowsWhenEncodingFloat(t *testing.T) { +func TestEncodingFloat(t *testing.T) { _, err := EncodeBuf(1.5, nil) if err == nil { - t.Fatalf("expected Error, got nil") + t.Fatal(err) } } func TestFloat16Loads(t *testing.T) { - decoded, err := NewDecoderFromBytes(append([]byte{0x10}, bytes.Repeat([]byte{0x11}, 2)...), nil).Decode() - object := Raw(append([]byte{0x10}, bytes.Repeat([]byte{0x11}, 2)...)) + bin := append([]byte{0x10}, bytes.Repeat([]byte{0x11}, 2)...) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %v", err) + t.Fatal(err) } - udecoded, ok := decoded.(Raw) + casted, ok := decoded.(Raw) if !ok { - t.Fatalf("expected Raw, got %v", reflect.TypeOf(decoded)) + t.Fatal("failed to cast") } - if !bytes.Equal(object, udecoded) { - t.Fatalf("expected %v, got %v", object, decoded) + if !bytes.Equal(casted, bin) { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } func TestFloat32Loads(t *testing.T) { - decoded, err := NewDecoderFromBytes(append([]byte{0x11}, bytes.Repeat([]byte{0x11}, 4)...), nil).Decode() - object := Raw(append([]byte{0x11}, bytes.Repeat([]byte{0x11}, 4)...)) + bin := append([]byte{0x11}, bytes.Repeat([]byte{0x11}, 4)...) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %v", err) + t.Fatal(err) } - udecoded, ok := decoded.(Raw) + casted, ok := decoded.(Raw) if !ok { - t.Fatalf("expected Raw, got %v", reflect.TypeOf(decoded)) + t.Fatal("failed to cast") + } + if !bytes.Equal(casted, bin) { + t.Fatal("casted differs") } - if !bytes.Equal(object, udecoded) { - t.Fatalf("expected %v, got %v", object, decoded) + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } func TestFloat64Loads(t *testing.T) { - decoded, err := NewDecoderFromBytes(append([]byte{0x12}, bytes.Repeat([]byte{0x11}, 8)...), nil).Decode() - object := Raw(append([]byte{0x12}, bytes.Repeat([]byte{0x11}, 8)...)) + bin := append([]byte{0x12}, bytes.Repeat([]byte{0x12}, 8)...) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %v", err) + t.Fatal(err) } - udecoded, ok := decoded.(Raw) + casted, ok := decoded.(Raw) if !ok { - t.Fatalf("expected Raw, got %v", reflect.TypeOf(decoded)) + t.Fatal("failed to cast") + } + if !bytes.Equal(casted, bin) { + t.Fatal("casted differs") } - if !bytes.Equal(object, udecoded) { - t.Fatalf("expected %v, got %v", object, decoded) + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } func TestFloat128Loads(t *testing.T) { - decoded, err := NewDecoderFromBytes(append([]byte{0x13}, bytes.Repeat([]byte{0x11}, 16)...), nil).Decode() - object := Raw(append([]byte{0x13}, bytes.Repeat([]byte{0x11}, 16)...)) + bin := append([]byte{0x13}, bytes.Repeat([]byte{0x13}, 16)...) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %v", err) + t.Fatal(err) } - udecoded, ok := decoded.(Raw) + casted, ok := decoded.(Raw) if !ok { - t.Fatalf("expected Raw, got %v", reflect.TypeOf(decoded)) + t.Fatal("failed to cast") } - if !bytes.Equal(object, udecoded) { - t.Fatalf("expected %v, got %v", object, decoded) + if !bytes.Equal(casted, bin) { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } func TestFloat256Loads(t *testing.T) { - decoded, err := NewDecoderFromBytes(append([]byte{0x14}, bytes.Repeat([]byte{0x11}, 32)...), nil).Decode() - object := Raw(append([]byte{0x14}, bytes.Repeat([]byte{0x11}, 32)...)) + bin := append([]byte{0x14}, bytes.Repeat([]byte{0x14}, 32)...) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %v", err) + t.Fatal(err) } - udecoded, ok := decoded.(Raw) + casted, ok := decoded.(Raw) if !ok { - t.Fatalf("expected Raw, got %v", reflect.TypeOf(decoded)) + t.Fatal("failed to cast") + } + if !bytes.Equal(casted, bin) { + t.Fatal("casted differs") } - if !bytes.Equal(object, udecoded) { - t.Fatalf("expected %v, got %v", object, decoded) + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestFloatThrowhsWhenNotEnoughDataForFloat256(t *testing.T) { - _, err := NewDecoderFromBytes(append([]byte{0x14}, bytes.Repeat([]byte{0x11}, 32-1)...), nil).Decode() +func TestFloat16NotEnoughData(t *testing.T) { + bin := append([]byte{0x10}, bytes.Repeat([]byte{0x11}, 2-1)...) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %s", err) + t.Fatal(err) } } -func TestFloatThrowhsWhenNotEnoughDataForFloat128(t *testing.T) { - _, err := NewDecoderFromBytes(append([]byte{0x13}, bytes.Repeat([]byte{0x11}, 16-1)...), nil).Decode() +func TestFloat32NotEnoughData(t *testing.T) { + bin := append([]byte{0x11}, bytes.Repeat([]byte{0x11}, 4-1)...) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %s", err) + t.Fatal(err) } } -func TestFloatThrowhsWhenNotEnoughDataForFloat64(t *testing.T) { - _, err := NewDecoderFromBytes(append([]byte{0x12}, bytes.Repeat([]byte{0x11}, 8-1)...), nil).Decode() +func TestFloat64NotEnoughData(t *testing.T) { + bin := append([]byte{0x12}, bytes.Repeat([]byte{0x11}, 8-1)...) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %s", err) + t.Fatal(err) } } -func TestFloatThrowhsWhenNotEnoughDataForFloat32(t *testing.T) { - _, err := NewDecoderFromBytes(append([]byte{0x11}, bytes.Repeat([]byte{0x11}, 4-1)...), nil).Decode() +func TestFloat128NotEnoughData(t *testing.T) { + bin := append([]byte{0x13}, bytes.Repeat([]byte{0x11}, 16-1)...) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %s", err) + t.Fatal(err) } } -func TestFloatThrowhsWhenNotEnoughDataForFloat16(t *testing.T) { - _, err := NewDecoderFromBytes(append([]byte{0x10}, bytes.Repeat([]byte{0x11}, 2-1)...), nil).Decode() +func TestFloat256NotEnoughData(t *testing.T) { + bin := append([]byte{0x14}, bytes.Repeat([]byte{0x11}, 32-1)...) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %s", err) + t.Fatal(err) } } diff --git a/go/generic_test.go b/go/generic_test.go index e7ad006..738b009 100644 --- a/go/generic_test.go +++ b/go/generic_test.go @@ -1,5 +1,6 @@ // GoKEKS -- Go KEKS codec implementation // Copyright (C) 2024-2025 Anton Rudenko +// Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as @@ -20,26 +21,24 @@ import ( "testing" ) -func TestThrowsWhenUnknownTag(t *testing.T) { - binstring := []byte{0x05} - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestUnknownTag(t *testing.T) { + _, err := NewDecoderFromBytes(append([]byte{0x05}, Junk...), nil).Decode() if err != ErrUnknownType { - t.Fatalf("expected ErrUnknownType, got %v", err) + t.Fatal(err) } } -func TestThrowsWhenEmptyData(t *testing.T) { +func TestEmptyData(t *testing.T) { binstring := []byte{} _, err := NewDecoderFromBytes(binstring, nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %v", err) + t.Fatal(err) } } func TestLonelyEOC(t *testing.T) { - binstring := []byte{0x00} - _, err := NewDecoderFromBytes(binstring, nil).Decode() + _, err := NewDecoderFromBytes(append([]byte{0x00}, Junk...), nil).Decode() if err != ErrUnexpectedEOC { - t.Fatalf("expected ErrUnexpectedEOC, got %v", err) + t.Fatal(err) } } diff --git a/go/hex_test.go b/go/hex_test.go new file mode 100644 index 0000000..fcedbe5 --- /dev/null +++ b/go/hex_test.go @@ -0,0 +1,13 @@ +package keks + +import ( + "encoding/hex" +) + +func mustHexDec(s string) []byte { + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return b +} diff --git a/go/int_test.go b/go/int_test.go index fbfc886..de40f88 100644 --- a/go/int_test.go +++ b/go/int_test.go @@ -1,5 +1,6 @@ // GoKEKS -- Go KEKS codec implementation // Copyright (C) 2024-2025 Anton Rudenko +// Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as @@ -17,683 +18,641 @@ package keks import ( "bytes" - "encoding/hex" "io" "math/big" - "reflect" "testing" "testing/quick" ) -func TestIntZero(t *testing.T) { - object := 0 - binstring := mustHexDec("0C80") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestInt0(t *testing.T) { + obj := int(0) + bin := mustHexDec("0C80") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) + } + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") + } + casted, ok := decoded.(uint64) + if !ok { + t.Fatal("failed to cast") } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if casted != uint64(obj) { + t.Fatal("casted differs") } - if decoded != uint64(object) { - t.Logf("expected type %s, value %d", reflect.TypeOf(object), object) - t.Logf("got type %s, value %d", reflect.TypeOf(decoded), decoded) - t.FailNow() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestIntOne(t *testing.T) { - object := 1 - binstring := mustHexDec("0C8101") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestInt1(t *testing.T) { + obj := int(1) + bin := mustHexDec("0C8101") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) + } + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + casted, ok := decoded.(uint64) + if !ok { + t.Fatal("failed to cast") + } + if casted != uint64(obj) { + t.Fatal("casted differs") } - if decoded != uint64(object) { - t.Logf("expected type %s, value %d", reflect.TypeOf(object), object) - t.Logf("got type %s, value %d", reflect.TypeOf(decoded), decoded) - t.FailNow() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestIntNegativeOne(t *testing.T) { - object := -1 - binstring := mustHexDec("0D80") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestIntM1(t *testing.T) { + obj := int(-1) + bin := mustHexDec("0D80") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - if decoded != int64(object) { - t.Logf("expected type %s, value %d", reflect.TypeOf(object), object) - t.Logf("got type %s, value %d", reflect.TypeOf(decoded), decoded) - t.FailNow() + casted, ok := decoded.(int64) + if !ok { + t.Fatal("failed to cast") + } + if casted != int64(obj) { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestInt1s63Minus1(t *testing.T) { - object := uint64(1<<63 - 1) - binstring := mustHexDec("0c887fffffffffffffff") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestInt123(t *testing.T) { + obj := uint(123) + bin := mustHexDec("0C817B") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - if err != nil { - t.Fatalf("error during decode: %s", err) + casted, ok := decoded.(uint64) + if !ok { + t.Fatal("failed to cast") + } + if casted != uint64(obj) { + t.Fatal("casted differs") } - if decoded != object { - t.Logf("expected type %s, value %d", reflect.TypeOf(object), object) - t.Logf("got type %s, value %d", reflect.TypeOf(decoded), decoded) - t.FailNow() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestInt1s63(t *testing.T) { - object, _ := big.NewInt(0).SetString("18446744073709551616", 10) - binstring := mustHexDec("0c89010000000000000000") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestIntM123(t *testing.T) { + obj := int(-123) + bin := mustHexDec("0D817A") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) - t.Log(hex.EncodeToString(encoded)) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + t.Fatal(err) } - if err != nil { - t.Fatalf("error during decode: %s", err) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - udecoded, ok := decoded.(*big.Int) + casted, ok := decoded.(int64) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") } - if udecoded.Cmp(object) != 0 { - t.Logf("expected type %s, value %d", reflect.TypeOf(object), object) - t.Logf("got type %s, value %d", reflect.TypeOf(decoded), decoded) - t.FailNow() + if casted != int64(obj) { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestInt1s64(t *testing.T) { - object := big.NewInt(1).SetBytes(mustHexDec("010000000000000000")) - binstring := mustHexDec("0C89010000000000000000") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestIntMaxAllowable(t *testing.T) { + obj := uint64(1<<63) - 1 + bin := mustHexDec("0C887FFFFFFFFFFFFFFF") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - if err != nil { - t.Fatalf("error during decode: %s", err) + casted, ok := decoded.(uint64) + if !ok { + t.Fatal("failed to cast") + } + if casted != uint64(obj) { + t.Fatal("casted differs") } - if decoded.(*big.Int).Cmp(object) != 0 { - t.Logf("expected type %s, value %d", reflect.TypeOf(object), object) - t.Logf("got type %s, value %d", reflect.TypeOf(decoded), decoded) - t.FailNow() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestInt1s130(t *testing.T) { - object := big.NewInt(1).SetBytes(mustHexDec("0400000000000000000000000000000000")) - binstring := mustHexDec("0C910400000000000000000000000000000000") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestIntNMaxAllowable(t *testing.T) { + obj := -int64(uint64(1<<63) - 1) + bin := mustHexDec("0D887FFFFFFFFFFFFFFE") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - if err != nil { - t.Fatalf("error during decode: %s", err) + casted, ok := decoded.(int64) + if !ok { + t.Fatal("failed to cast") } - if decoded.(*big.Int).Cmp(object) != 0 { - t.Logf("expected type %s, value %d", reflect.TypeOf(object), object) - t.Logf("got type %s, value %d", reflect.TypeOf(decoded), decoded) - t.FailNow() + if casted != obj { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestIntM1s62Plus1(t *testing.T) { - object := int64(-9223372036854775808) - binstring := mustHexDec("0D887FFFFFFFFFFFFFFF") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestInt64bit(t *testing.T) { + obj := big.NewInt(0) + obj = obj.SetBit(obj, 64, 1) + bin := mustHexDec("0C89010000000000000000") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) + } + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") + } + casted, ok := decoded.(*big.Int) + if !ok { + t.Fatal("failed to cast") } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if casted.Cmp(obj) != 0 { + t.Fatal("casted differs") } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } +} + +func TestIntM64bit(t *testing.T) { + obj := big.NewInt(0) + obj = obj.SetBit(obj, 64, 1) + obj = obj.Neg(obj) + bin := mustHexDec("0D88FFFFFFFFFFFFFFFF") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() + if err != nil { + t.Fatal(err) + } + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) + } + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - udecoded, ok := decoded.(int64) + casted, ok := decoded.(*big.Int) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") } - if udecoded != object { - t.Logf("expected type %s, value %d", reflect.TypeOf(object), object) - t.Logf("got type %s, value %d", reflect.TypeOf(decoded), decoded) - t.FailNow() + if casted.Cmp(obj) != 0 { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestIntM1s62(t *testing.T) { - object, _ := big.NewInt(0).SetString("-9223372036854775809", 10) - binstring := mustHexDec("0D888000000000000000") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestIntM64bitAnd1(t *testing.T) { + obj := big.NewInt(0) + obj = obj.SetBit(obj, 64, 1) + obj = obj.SetBit(obj, 0, 1) + obj = obj.Neg(obj) + bin := mustHexDec("0D89010000000000000000") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - if err != nil { - t.Fatalf("error during decode: %s", err) + casted, ok := decoded.(*big.Int) + if !ok { + t.Fatal("failed to cast") + } + if casted.Cmp(obj) != 0 { + t.Fatal("casted differs") } - if decoded.(*big.Int).Cmp(object) != 0 { - t.Logf("expected type %s, value %d", reflect.TypeOf(object), object) - t.Logf("got type %s, value %d", reflect.TypeOf(decoded), decoded) - t.FailNow() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestIntM1s64(t *testing.T) { - object := big.NewInt(0).SetBytes(mustHexDec("010000000000000000")) - object = object.Neg(object) - binstring := mustHexDec("0D88FFFFFFFFFFFFFFFF") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestInt131bit(t *testing.T) { + obj := big.NewInt(0) + obj = obj.SetBit(obj, 130, 1) + bin := mustHexDec("0C910400000000000000000000000000000000") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - if err != nil { - t.Fatalf("error during decode: %s", err) + casted, ok := decoded.(*big.Int) + if !ok { + t.Fatal("failed to cast") } - if decoded.(*big.Int).Cmp(object) != 0 { - t.Logf("expected type %s, value %d", reflect.TypeOf(object), object) - t.Logf("got type %s, value %d", reflect.TypeOf(decoded), decoded) - t.FailNow() + if casted.Cmp(obj) != 0 { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestIntM1s130(t *testing.T) { - object := big.NewInt(1).SetBytes(mustHexDec("0100000000000000000000000000000000")) - object = object.Neg(object) - binstring := mustHexDec("0D90FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestIntM131bit(t *testing.T) { + obj := big.NewInt(0) + obj = obj.SetBit(obj, 130, 1) + obj = obj.Neg(obj) + bin := mustHexDec("0D9103FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - if err != nil { - t.Fatalf("error during decode: %s", err) + casted, ok := decoded.(*big.Int) + if !ok { + t.Fatal("failed to cast") } - if decoded.(*big.Int).Cmp(object) != 0 { - t.Logf("expected type %s, value %d", reflect.TypeOf(object), object) - t.Logf("got type %s, value %d", reflect.TypeOf(decoded), decoded) - t.FailNow() + if casted.Cmp(obj) != 0 { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestIntThrowsWhenNotEnoughData(t *testing.T) { +func TestIntNotEnoughData(t *testing.T) { _, err := NewDecoderFromBytes(mustHexDec("0C830102"), nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected error, got %v", err) + t.Fatal(err) } _, err = NewDecoderFromBytes(mustHexDec("0C8301"), nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected error, got %v", err) + t.Fatal(err) } } -func TestIntThrowsWhenNonMinimalInt(t *testing.T) { +func TestIntNonMinimalInt(t *testing.T) { encoded := mustHexDec("0C81007B") _, err := NewDecoderFromBytes(encoded, nil).Decode() if err != ErrIntNonMinimal { - t.Fatalf("expected ErrIntNonMinimal, got %v", err) + t.Fatal(err) } } -func TestIntThrowsWhenNonBinInInt(t *testing.T) { +func TestIntNonBinInInt(t *testing.T) { encoded := mustHexDec("0C017B") _, err := NewDecoderFromBytes(encoded, nil).Decode() if err != ErrBadInt { - t.Fatalf("expected ErrBadInt, got %v", err) - } -} - -func TestInt64UnsignedSymmetric(t *testing.T) { - f := func(x uint64) bool { - encoded, err := EncodeBuf(x, nil) - if err != nil { - t.Logf("error during encode: %s", err) - return false - } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() - if err != nil { - t.Logf("error during decode: %s", err) - return false - } - udecoded, ok := decoded.(uint64) - if !ok { - t.Logf("failed to cast") - return false - } - if uint64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false - } - return true - } - if err := quick.Check(f, nil); err != nil { t.Fatal(err) } } -func TestInt32UnsignedSymmetric(t *testing.T) { - f := func(x uint32) bool { +func TestInt64Symmetric(t *testing.T) { + f := func(x uint64) bool { encoded, err := EncodeBuf(x, nil) if err != nil { - t.Logf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) - return false + t.Fatal(err) } - udecoded, ok := decoded.(uint64) + casted, ok := decoded.(uint64) if !ok { - t.Logf("failed to cast") - return false + t.Fatal("failed to cast") } - if uint64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - return true + return casted == x } if err := quick.Check(f, nil); err != nil { t.Fatal(err) } } -func TestInt16UnsignedSymmetric(t *testing.T) { - f := func(x uint16) bool { - encoded, err := EncodeBuf(x, nil) - if err != nil { - t.Logf("error during encode: %s", err) - return false - } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() - if err != nil { - t.Logf("error during decode: %s", err) - return false - } - udecoded, ok := decoded.(uint64) - if !ok { - t.Logf("failed to cast") - return false - } - if uint64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false +func TestInt64NSymmetric(t *testing.T) { + f := func(x int64) bool { + if x >= 0 { + return true } - return true - } - if err := quick.Check(f, nil); err != nil { - t.Fatal(err) - } -} - -func TestInt8UnsignedSymmetric(t *testing.T) { - f := func(x uint8) bool { encoded, err := EncodeBuf(x, nil) if err != nil { - t.Logf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) - return false + t.Fatal(err) } - udecoded, ok := decoded.(uint64) + casted, ok := decoded.(int64) if !ok { - t.Logf("failed to cast") - return false + t.Fatal("failed to cast") } - if uint64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - return true + return casted == x } if err := quick.Check(f, nil); err != nil { t.Fatal(err) } } -func TestInt32PositiveSymmetric(t *testing.T) { - f := func(x int32) bool { - if x == -1<<31 { - return true - } - if x < 0 { - x = -x - } +func TestInt32Symmetric(t *testing.T) { + f := func(x uint32) bool { encoded, err := EncodeBuf(x, nil) if err != nil { - t.Logf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) - return false + t.Fatal(err) } - udecoded, ok := decoded.(uint64) + casted, ok := decoded.(uint64) if !ok { - t.Logf("failed to cast") - return false + t.Fatal("failed to cast") } - if uint64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - return true + return casted == uint64(x) } if err := quick.Check(f, nil); err != nil { t.Fatal(err) } } -func TestInt32NegativeSymmetric(t *testing.T) { +func TestInt32NSymmetric(t *testing.T) { f := func(x int32) bool { - if x > 0 { - x = -x - } - if x == 0 { + if x >= 0 { return true } encoded, err := EncodeBuf(x, nil) if err != nil { - t.Logf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) - return false + t.Fatal(err) } - udecoded, ok := decoded.(int64) + casted, ok := decoded.(int64) if !ok { - t.Logf("failed to cast") - return false + t.Fatal("failed to cast") } - if int64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - return true + return casted == int64(x) } if err := quick.Check(f, nil); err != nil { t.Fatal(err) } } -func TestInt16PositiveSymmetric(t *testing.T) { - f := func(x int16) bool { - if x == -1<<15 { - return true - } - if x < 0 { - x = -x - } +func TestInt16Symmetric(t *testing.T) { + f := func(x uint16) bool { encoded, err := EncodeBuf(x, nil) if err != nil { - t.Logf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) - return false + t.Fatal(err) } - udecoded, ok := decoded.(uint64) + casted, ok := decoded.(uint64) if !ok { - t.Logf("failed to cast") - return false + t.Fatal("failed to cast") } - if uint64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - return true + return casted == uint64(x) } if err := quick.Check(f, nil); err != nil { t.Fatal(err) } } -func TestInt16NegativeSymmetric(t *testing.T) { +func TestInt16NSymmetric(t *testing.T) { f := func(x int16) bool { - if x > 0 { - x = -x - } - if x == 0 { + if x >= 0 { return true } encoded, err := EncodeBuf(x, nil) if err != nil { - t.Logf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) - return false + t.Fatal(err) } - udecoded, ok := decoded.(int64) + casted, ok := decoded.(int64) if !ok { - t.Logf("failed to cast") - return false + t.Fatal("failed to cast") } - if int64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - return true + return casted == int64(x) } if err := quick.Check(f, nil); err != nil { t.Fatal(err) } } -func TestInt8PositiveSymmetric(t *testing.T) { - f := func(x int8) bool { - if x == -1<<7 { - return true - } - if x < 0 { - x = -x - } +func TestInt8Symmetric(t *testing.T) { + f := func(x uint8) bool { encoded, err := EncodeBuf(x, nil) if err != nil { - t.Logf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) - return false + t.Fatal(err) } - udecoded, ok := decoded.(uint64) + casted, ok := decoded.(uint64) if !ok { - t.Logf("failed to cast") - return false + t.Fatal("failed to cast") } - if uint64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - return true + return casted == uint64(x) } if err := quick.Check(f, nil); err != nil { t.Fatal(err) } } -func TestInt8NegativeSymmetric(t *testing.T) { +func TestInt8NSymmetric(t *testing.T) { f := func(x int8) bool { - if x > 0 { - x = -x - } - if x == 0 { + if x >= 0 { return true } encoded, err := EncodeBuf(x, nil) if err != nil { - t.Logf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) - return false + t.Fatal(err) } - udecoded, ok := decoded.(int64) + casted, ok := decoded.(int64) if !ok { - t.Logf("failed to cast") - return false + t.Fatal("failed to cast") } - if int64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - return true + return casted == int64(x) } if err := quick.Check(f, nil); err != nil { t.Fatal(err) } } -func TestInt64PositiveSymmetric(t *testing.T) { - f := func(x int64) bool { - if x < 0 { - x = -x - } +func TestIntBigSymmetric(t *testing.T) { + f := func(l uint8) bool { + data := make([]byte, 8+1+int(l)) + if _, err := io.ReadFull(PRNG, data); err != nil { + panic(err) + } + data[0] |= 0x80 // be sure that is really a big number + x := big.NewInt(0).SetBytes(data) encoded, err := EncodeBuf(x, nil) if err != nil { - t.Logf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) - return false + t.Fatal(err) } - udecoded, ok := decoded.(uint64) + casted, ok := decoded.(*big.Int) if !ok { - t.Logf("failed to cast") - return false + t.Fatal("failed to cast") } - if uint64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - return true + return casted.Cmp(x) == 0 } if err := quick.Check(f, nil); err != nil { t.Fatal(err) } } -func TestInt64NegativeSymmetric(t *testing.T) { - f := func(x int64) bool { - if x > 0 { - x = -x - } - if x == 0 { - return true - } +func TestIntNBigSymmetric(t *testing.T) { + f := func(l uint8) bool { + data := make([]byte, 8+1+int(l)) + if _, err := io.ReadFull(PRNG, data); err != nil { + panic(err) + } + data[0] |= 0x80 // be sure that is really a big number + x := big.NewInt(0).SetBytes(data) + x = x.Neg(x) encoded, err := EncodeBuf(x, nil) if err != nil { - t.Logf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) - return false - + t.Fatal(err) } - udecoded, ok := decoded.(int64) + casted, ok := decoded.(*big.Int) if !ok { - t.Logf("failed to cast") - return false + t.Fatal("failed to cast") } - if int64(x) != udecoded { - t.Logf("Expected <%s, %d>, got <%s, %d>", reflect.TypeOf(x), x, reflect.TypeOf(decoded), decoded) - return false + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - return true + return casted.Cmp(x) == 0 } if err := quick.Check(f, nil); err != nil { t.Fatal(err) diff --git a/go/support_test.go b/go/junk_test.go similarity index 59% rename from go/support_test.go rename to go/junk_test.go index a57611d..7072a99 100644 --- a/go/support_test.go +++ b/go/junk_test.go @@ -1,5 +1,5 @@ // GoKEKS -- Go KEKS codec implementation -// Copyright (C) 2024-2025 Anton Rudenko +// Copyright (C) 2024-2025 Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as @@ -16,33 +16,25 @@ package keks import ( - "crypto/rand" - "encoding/hex" + crand "crypto/rand" "io" - mrand "math/rand" + "math/rand/v2" ) -func mustHexDec(s string) []byte { - b, err := hex.DecodeString(s) +var ( + PRNG *rand.ChaCha8 + Junk []byte +) + +func init() { + var seed [32]byte + _, err := io.ReadFull(crand.Reader, seed[:]) if err != nil { panic(err) } - return b -} - -func invalidUTF8_2Byte(x, y int) []byte { - return []byte{1<<7 | 1<<6 | byte(x), 1<<7 | 1<<6 | byte(y)} -} - -func invalidUTF8_3Byte(x, y, z int) []byte { - return []byte{(1<<7 | 1<<6 | 1<<5 | byte(x)), (1<<7 | byte(y)), (1<<7 | 1<<6 | byte(z))} -} - -var Junk []byte - -func init() { - Junk = make([]byte, 1+mrand.Intn(8)) - _, err := io.ReadFull(rand.Reader, Junk) + PRNG = rand.NewChaCha8(seed) + Junk = make([]byte, 1+rand.UintN(7)) + _, err = io.ReadFull(PRNG, Junk) if err != nil { panic(err) } diff --git a/go/list_test.go b/go/list_test.go index e28a806..1dd2464 100644 --- a/go/list_test.go +++ b/go/list_test.go @@ -1,5 +1,6 @@ // GoKEKS -- Go KEKS codec implementation // Copyright (C) 2024-2025 Anton Rudenko +// Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as @@ -17,71 +18,103 @@ package keks import ( "bytes" - "encoding/hex" "io" - "reflect" + "math/rand/v2" "slices" "testing" "testing/quick" ) func TestListEmpty(t *testing.T) { - object := []any{} - binstring := []byte("\x08\x00") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() + obj := []any{} + bin := []byte{0x08, 0x00} + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + t.Fatal(err) } - if err != nil { - t.Fatalf("error during encode: %s", err) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - udecoded, ok := decoded.([]any) + casted, ok := decoded.([]any) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") + } + if !slices.Equal(obj, casted) { + t.Fatal("casted differs") } - if !slices.Equal(object, udecoded) { - t.Logf("expected type %s, value true", reflect.TypeOf(object)) - t.Logf("got type %s, value %t", reflect.TypeOf(decoded), decoded) - t.FailNow() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestListThrowsWhenNoEOC(t *testing.T) { - binstring := []byte("\x08") - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestListNoEOC(t *testing.T) { + encoded, err := EncodeBuf([]int{123}, nil) + if err != nil { + t.Fatal(err) + } + _, err = NewDecoderFromBytes(encoded[:len(encoded)-1], nil).Decode() if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %v", err) + t.Fatal(err) + } +} + +func TestListMaxContLen(t *testing.T) { + l := 2 + rand.UintN(8) + bin, err := EncodeBuf(make([]int, l), nil) + if err != nil { + t.Fatal(err) + } + decoder := NewDecoderFromBytes(bin, nil) + _, err = decoder.Decode() + if err != nil { + t.Fatal(err) + } + decoder = NewDecoderFromBytes(bin, &DecodeOpts{MaxContLen: int64(l) + 1}) + _, err = decoder.Decode() + if err != nil { + t.Fatal(err) + } + decoder = NewDecoderFromBytes(bin, &DecodeOpts{MaxContLen: int64(l)}) + _, err = decoder.Decode() + if err != ErrLenTooBig { + t.Fatal(err) } } func TestListIntSymmetric(t *testing.T) { - f := func(x []uint64) bool { - encoded, err := EncodeBuf(x, nil) + f := func(vs []int64) bool { + encoded, err := EncodeBuf(vs, nil) if err != nil { - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - return false + t.Fatal(err) } - udecoded, ok := decoded.([]any) + casted, ok := decoded.([]any) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") } - if len(x) != len(udecoded) { + if len(vs) != len(casted) { return false } - for i := range x { - if x[i] != udecoded[i] { - t.Logf("Expected <%s, %d>", reflect.TypeOf(x), x) - t.Logf("Instead <%s, %d>", reflect.TypeOf(decoded), decoded) + for i := range len(vs) { + switch v := casted[i].(type) { + case uint64: + if v != uint64(vs[i]) { + return false + } + case int64: + if v != int64(vs[i]) { + return false + } + default: return false } } diff --git a/go/magic_test.go b/go/magic_test.go new file mode 100644 index 0000000..4efe285 --- /dev/null +++ b/go/magic_test.go @@ -0,0 +1,74 @@ +// GoKEKS -- Go KEKS codec implementation +// Copyright (C) 2024-2025 Sergey Matveev +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, version 3 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program. If not, see . + +package keks + +import ( + "bytes" + "io" + "strings" + "testing" + "testing/quick" +) + +func TestMagicSymmetric(t *testing.T) { + f := func(m [12]byte) bool { + encoded, err := EncodeBuf(Magic(m[:]), nil) + if err != nil { + t.Fatal(err) + } + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() + if err != nil { + t.Fatal(err) + } + casted, ok := decoded.(Magic) + if !ok { + t.Fatal("failed to cast") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } + return string(casted) == strings.TrimRight(string(m[:]), "\x00") + } + if err := quick.Check(f, nil); err != nil { + t.Fatal(err) + } +} + +func TestMagicNotEnoughData(t *testing.T) { + encoded, err := EncodeBuf(Magic("something"), nil) + if err != nil { + t.Fatal(err) + } + decoder := NewDecoderFromBytes(encoded[:len(encoded)-1], nil) + _, err = decoder.Decode() + if err != io.ErrUnexpectedEOF { + t.Fatal(err) + } +} + +func TestMagicBadMagic(t *testing.T) { + encoded, err := EncodeBuf(Magic("something"), nil) + if err != nil { + t.Fatal(err) + } + encoded[2] = 'e' + decoder := NewDecoderFromBytes(encoded, nil) + _, err = decoder.Decode() + if err != ErrBadMagic { + t.Fatal(err) + } +} diff --git a/go/map_test.go b/go/map_test.go index d3de806..9ae8693 100644 --- a/go/map_test.go +++ b/go/map_test.go @@ -1,5 +1,6 @@ // GoKEKS -- Go KEKS codec implementation // Copyright (C) 2024-2025 Anton Rudenko +// Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as @@ -17,109 +18,166 @@ package keks import ( "bytes" - "encoding/hex" - "maps" - "reflect" + "math/rand/v2" + "strconv" "testing" "testing/quick" ) func TestMapEmpty(t *testing.T) { - binstring := []byte("\x09\x00") - object := make(map[string]any) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() + bin := []byte("\x09\x00") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - encoded, err := EncodeBuf(object, nil) + encoded, err := EncodeBuf(struct{}{}, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") } - if err != nil { - t.Fatalf("error during decode: %s", err) - } - udecoded, ok := decoded.(map[string]any) + casted, ok := decoded.(map[string]any) if !ok { - t.Fatalf("failed to cast") + t.Fatal("failed to cast") + } + if len(casted) != 0 { + t.Fatal("casted differs") } - if !maps.Equal(object, udecoded) { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(decoded), decoded) - t.Fail() + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } } -func TestMapThrowsWhenNonStringKey(t *testing.T) { - object := make(map[any]any) - object[1] = "a" - binstring := []byte("\x09\x0C\x80\xC6value2\x00") - _, err := EncodeBuf(object, nil) +func TestMapEncodeNonStrKey(t *testing.T) { + _, err := EncodeBuf(map[any]any{123: 123}, nil) if err != ErrMapBadKey { - t.Fatalf("expected ErrMapBadKey during encode, got %v", err) + t.Fatal(err) } - _, err = NewDecoderFromBytes(binstring, nil).Decode() +} + +func TestMapDecodeNonStrKey(t *testing.T) { + _, err := NewDecoderFromBytes([]byte("\x09\x0C\x80\xC6value2\x00"), nil).Decode() if err != ErrMapBadKey { - t.Fatalf("expected ErrMapBadKey during decode, got %v", err) + t.Fatal(err) } } -func TestMapThrowsWhenUnexpectedEOC(t *testing.T) { - binstring := []byte("\x09\xC4key1\x00\x00") - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestMapUnexpectedEOC(t *testing.T) { + _, err := NewDecoderFromBytes([]byte("\x09\xC4key1\x00\x00"), nil).Decode() if err != ErrUnexpectedEOC { - t.Fatalf("expected ErrUnexpectedEOC during decode, got %v", err) + t.Fatal(err) } } -func TestMapThrowsWhenEmptyStringKeyEncode(t *testing.T) { - object := make(map[any]any) - object[""] = "a" - _, err := EncodeBuf(object, nil) +func TestMapEncodeEmptyStrKey(t *testing.T) { + _, err := EncodeBuf(map[string]any{"": 123}, nil) if err != ErrMapBadKey { - t.Fatalf("expected ErrMapBadKey during encode, got %v", err) + t.Fatal(err) } } -func TestMapThrowsWhenEmptyStringKeyDecode(t *testing.T) { - binstring := []byte("\x09\xC0\x0C\x81\x01\xC4key1\xC6value1\x00") - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestMapDecodeEmptyStrKey(t *testing.T) { + _, err := NewDecoderFromBytes(mustHexDec("09C0C000"), nil).Decode() if err != ErrMapBadKey { - t.Fatalf("expected ErrMapBadKey during decode, got %v", err) + t.Fatal(err) + } +} + +func TestMapUnsortedValueKeys(t *testing.T) { + bin := bytes.Join([][]byte{ + mustHexDec("09"), + mustHexDec("C4"), []byte("key2"), + mustHexDec("0C8101"), + mustHexDec("C4"), []byte("key1"), + mustHexDec("C6"), []byte("value1"), + mustHexDec("00"), + }, nil) + _, err := NewDecoderFromBytes(bin, nil).Decode() + if err != ErrMapUnordered { + t.Fatal(err) } } -func TestMapThrowsWhenUnsortedKeys(t *testing.T) { - binstring := []byte("\x09\xC4key2\xC6value2\xC4key1\xC6value1\x00") - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestMapUnsortedLenKeys(t *testing.T) { + bin := bytes.Join([][]byte{ + mustHexDec("09"), + mustHexDec("C4"), []byte("key2"), + mustHexDec("0C8101"), + mustHexDec("C3"), []byte("key"), + mustHexDec("C6"), []byte("value1"), + mustHexDec("00"), + }, nil) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != ErrMapUnordered { - t.Fatalf("expected ErrMapUnordered during decode, got %v", err) + t.Fatal(err) + } +} + +func TestMapMaxContLen(t *testing.T) { + l := 2 + rand.UintN(8) + m := make(map[string]int, l) + for i := range l { + m[strconv.Itoa(int(i))] = 123 + } + bin, err := EncodeBuf(m, nil) + if err != nil { + t.Fatal(err) + } + decoder := NewDecoderFromBytes(bin, nil) + _, err = decoder.Decode() + if err != nil { + t.Fatal(err) + } + decoder = NewDecoderFromBytes(bin, &DecodeOpts{MaxContLen: int64(l) + 1}) + _, err = decoder.Decode() + if err != nil { + t.Fatal(err) + } + decoder = NewDecoderFromBytes(bin, &DecodeOpts{MaxContLen: int64(l)}) + _, err = decoder.Decode() + if err != ErrLenTooBig { + t.Fatal(err) } } func TestMapIntSymmetric(t *testing.T) { - f := func(x map[string]uint64) bool { - delete(x, "") - encoded, err := EncodeBuf(x, nil) + f := func(m map[int]uint64) bool { + obj := make(map[string]uint64, len(m)) + for k, v := range m { + obj[strconv.Itoa(k)] = v + } + m = nil + encoded, err := EncodeBuf(obj, nil) if err != nil { - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) - return false + t.Fatal(err) } - udecoded, ok := decoded.(map[string]any) + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } + casted, ok := decoded.(map[string]any) if !ok { - t.Logf("failed to cast") + t.Fatal("failed to cast") + } + if len(casted) != len(obj) { return false } - for k := range x { - if x[k] != udecoded[k] { - t.Logf("expected <%s, %v>", reflect.TypeOf(x), x) - t.Logf("instead <%s, %v>", reflect.TypeOf(udecoded), udecoded) + for k := range obj { + v, ok := casted[k] + if !ok { + return false + } + i, ok := v.(uint64) + if !ok { + t.Fatal("failed to cast") + } + if i != obj[k] { return false } } diff --git a/go/parse.go b/go/parse.go index 5a7daee..3426f8c 100644 --- a/go/parse.go +++ b/go/parse.go @@ -121,6 +121,12 @@ func (ctx *Decoder) parse() (t types.Type, err error) { return } count++ + if ctx.opts != nil && + ctx.opts.MaxContLen > 0 && + int64(count) >= ctx.opts.MaxContLen { + err = ErrLenTooBig + return + } } ctx.lens[idx] = count ctx.depth-- diff --git a/go/str_test.go b/go/str_test.go new file mode 100644 index 0000000..273a104 --- /dev/null +++ b/go/str_test.go @@ -0,0 +1,397 @@ +// GoKEKS -- Go KEKS codec implementation +// Copyright (C) 2024-2025 Anton Rudenko +// Sergey Matveev +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, version 3 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program. If not, see . + +package keks + +import ( + "bytes" + "io" + "math/rand" + "reflect" + "strings" + "testing" + "testing/quick" + + "go.cypherpunks.su/keks/be" +) + +func TestStrEmpty(t *testing.T) { + obj := "" + bin := mustHexDec("C0") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() + if err != nil { + t.Fatal(err) + } + encoded, err := EncodeBuf(obj, nil) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") + } + casted, ok := decoded.(string) + if !ok { + t.Fatal("failed to cast") + } + if casted != obj { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } +} + +func TestStrHelloWorld(t *testing.T) { + obj := "hello world" + bin := append([]byte{0xCB}, []byte("hello world")...) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() + if err != nil { + t.Fatal(err) + } + encoded, err := EncodeBuf(obj, nil) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") + } + casted, ok := decoded.(string) + if !ok { + t.Fatal("failed to cast") + } + if casted != obj { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } +} + +func TestStrПриветМир(t *testing.T) { + obj := "привет мир" + bin := append([]byte{0xD3}, []byte("привет мир")...) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() + if err != nil { + t.Fatal(err) + } + encoded, err := EncodeBuf(obj, nil) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") + } + casted, ok := decoded.(string) + if !ok { + t.Fatal("failed to cast") + } + if casted != obj { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } +} + +func TestStrLen62(t *testing.T) { + obj := strings.Repeat("a", 62) + bin := mustHexDec("FD01" + strings.Repeat("61", 62)) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() + if err != nil { + t.Fatal(err) + } + encoded, err := EncodeBuf(obj, nil) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") + } + casted, ok := decoded.(string) + if !ok { + t.Fatal("failed to cast") + } + if casted != obj { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } +} + +func TestStrLen318(t *testing.T) { + obj := strings.Repeat("a", 62+255+1) + bin := mustHexDec("FE0001" + strings.Repeat("61", 62+255+1)) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() + if err != nil { + t.Fatal(err) + } + encoded, err := EncodeBuf(obj, nil) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") + } + casted, ok := decoded.(string) + if !ok { + t.Fatal("failed to cast") + } + if casted != obj { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } +} + +func TestStrLen65853(t *testing.T) { + obj := strings.Repeat("a", 62+255+65535+1) + bin := mustHexDec("FF0000000000000000" + strings.Repeat("61", 62+255+65535+1)) + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() + if err != nil { + t.Fatal(err) + } + encoded, err := EncodeBuf(obj, nil) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") + } + casted, ok := decoded.(string) + if !ok { + t.Fatal("failed to cast") + } + if casted != obj { + t.Fatal("casted differs") + } + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } +} + +func TestStrNullByteInUTF8(t *testing.T) { + bin := []byte("\xC5he\x00\x01\x02") + _, err := NewDecoderFromBytes(bin, nil).Decode() + if err != ErrBadUTF8 { + t.Fatal(err) + } +} + +func TestStrNullByteInUTF8AndCheckDisabled(t *testing.T) { + bin := []byte("\xC5he\x00\x01\x02") + _, err := NewDecoderFromBytes(bin, &DecodeOpts{DisableUTF8Check: true}).Decode() + if err == ErrBadUTF8 { + t.Fatal(err) + } +} + +// Here go invalid UTF-8 byte(s) strategies. We can fail in following +// ways during decoding: +// * invalid start byte -- hypothesis generates integers that will +// satisfy that fail +// * invalid continuation byte -- we strip last byte of multibyte +// sequences +// * unexpected end of data -- we strip the last byte of our data + +func TestStrStripped2ByteInUTF8(t *testing.T) { + // 110xxxxx 10xxxxxx(STRIPPED) + f := func(x int) bool { + bin := []byte{0xC1, (1 << 7) | (1 << 6) | byte(x)} + _, err := NewDecoderFromBytes(bin, nil).Decode() + if err != ErrBadUTF8 { + return false + } + _, err = NewDecoderFromBytes(bin, + &DecodeOpts{DisableUTF8Check: true}).Decode() + return err == nil + } + if err := quick.Check(f, &quick.Config{ + Values: func(v []reflect.Value, r *rand.Rand) { + v[0] = reflect.ValueOf(r.Intn((1 << 5) - 1)) + }, + }); err != nil { + t.Fatal(err) + } +} + +func TestStrStripped3ByteInUTF8(t *testing.T) { + // 1110xxxx 10xxxxxx 10xxxxxx(STRIPPED) + f := func(x int) bool { + bin := []byte{ + 0xC2, + (1 << 7) | (1 << 6) | (1 << 5) | byte(x>>6), + byte((1 << 7) | (((1 << 6) - 1) & x)), + } + _, err := NewDecoderFromBytes(bin, nil).Decode() + if err != ErrBadUTF8 { + return false + } + _, err = NewDecoderFromBytes(bin, + &DecodeOpts{DisableUTF8Check: true}).Decode() + return err == nil + } + if err := quick.Check(f, &quick.Config{ + Values: func(v []reflect.Value, r *rand.Rand) { + v[0] = reflect.ValueOf(r.Intn((1 << 10) - 1)) + }, + }); err != nil { + t.Fatal(err) + } +} + +func TestStrNotEnoughData(t *testing.T) { + bin, err := EncodeBuf("hello", nil) + if err != nil { + panic(err) + } + _, err = NewDecoderFromBytes(bin[:len(bin)-1], nil).Decode() + if err != io.ErrUnexpectedEOF { + t.Fatal(err) + } +} + +func TestStrNotEnoughDataForLength8(t *testing.T) { + bin, err := EncodeBuf(strings.Repeat("f", 100), nil) + if err != nil { + panic(err) + } + _, err = NewDecoderFromBytes(bin[:len(bin)-1], nil).Decode() + if err != io.ErrUnexpectedEOF { + t.Fatal(err) + } +} + +func TestStrNotEnoughDataForLength16(t *testing.T) { + bin, err := EncodeBuf(strings.Repeat("f", 318), nil) + if err != nil { + panic(err) + } + _, err = NewDecoderFromBytes(bin[:len(bin)-1], nil).Decode() + if err != io.ErrUnexpectedEOF { + t.Fatal(err) + } +} + +func TestStrNotEnoughDataForLength64(t *testing.T) { + bin, err := EncodeBuf(strings.Repeat("f", 65853), nil) + if err != nil { + panic(err) + } + _, err = NewDecoderFromBytes(bin[:len(bin)-1], nil).Decode() + if err != io.ErrUnexpectedEOF { + t.Fatal(err) + } +} + +func TestStrTooLong(t *testing.T) { + bin := make([]byte, 9) + bin[0] = 0xFF + for _, l := range []uint64{ + 1 << 63, + (1 << 63) - 63, + (1 << 63) - 63 - ((1 << 8) - 1), + (1 << 63) - 63 - ((1 << 8) - 1) - ((1 << 16) - 1) + 1, + } { + be.Put(bin[1:], l) + decoder := NewDecoderFromBytes(bin, nil) + _, err := decoder.Decode() + if err != ErrLenTooBig { + t.Fatal(err) + } + } +} + +func TestStrNotTooLong(t *testing.T) { + bin := make([]byte, 9) + bin[0] = 0xFF + be.Put(bin[1:], (1<<63)-63-((1<<8)-1)-((1<<16)-1)) + decoder := NewDecoderFromReader(bytes.NewReader(bin), nil) + defer func() { recover() }() + _, err := decoder.Decode() + // it won't reach that code because it can not allocate so much + // memory in .getBytes(), but that means, that no error was returned + t.Fatal(err) +} + +func TestStrMaxStrLen(t *testing.T) { + f := func(str string) bool { + if str == "" { + return true + } + encoded, err := EncodeBuf(str, nil) + if err != nil { + panic(err) + } + decoder := NewDecoderFromBytes(encoded, + &DecodeOpts{DisableUTF8Check: true, MaxStrLen: int64(len(str) + 1)}) + _, err = decoder.Decode() + if err != nil { + return false + } + decoder = NewDecoderFromBytes(encoded, + &DecodeOpts{DisableUTF8Check: true, MaxStrLen: int64(len(str))}) + _, err = decoder.Decode() + if err != nil { + return false + } + if len(str) == 1 { + return true + } + decoder = NewDecoderFromBytes(encoded, + &DecodeOpts{DisableUTF8Check: true, MaxStrLen: int64(len(str) - 1)}) + _, err = decoder.Decode() + return err != nil + } + if err := quick.Check(f, nil); err != nil { + t.Fatal(err) + } +} + +func TestStrSymmetric(t *testing.T) { + f := func(str string) bool { + encoded, err := EncodeBuf(str, nil) + if err != nil { + panic(err) + } + decoder := NewDecoderFromBytes( + append(encoded, Junk...), + &DecodeOpts{DisableUTF8Check: true}, + ) + decoded, err := decoder.Decode() + if err != nil { + return false + } + casted, ok := decoded.(string) + if !ok { + return false + } + if str != casted { + return false + } + return bytes.Equal(decoder.B, Junk) + } + if err := quick.Check(f, nil); err != nil { + t.Fatal(err) + } +} diff --git a/go/string_test.go b/go/string_test.go deleted file mode 100644 index 8826260..0000000 --- a/go/string_test.go +++ /dev/null @@ -1,357 +0,0 @@ -// GoKEKS -- Go KEKS codec implementation -// Copyright (C) 2024-2025 Anton Rudenko -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, version 3 of the License. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this program. If not, see . - -package keks - -import ( - "bytes" - "encoding/hex" - "io" - mrand "math/rand" - "reflect" - "strings" - "testing" - "testing/quick" -) - -func TestStrEmpty(t *testing.T) { - object := "" - binstring := mustHexDec("C0") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != nil { - t.Fatalf("error during decode: %s", err) - } - encoded, err := EncodeBuf(object, nil) - if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) - } - if decoded != object { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(decoded), decoded) - t.FailNow() - } -} - -func TestStrHelloWorld(t *testing.T) { - object := "hello world" - binstring := bytes.Join([][]byte{mustHexDec("CB"), []byte("hello world")}, nil) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != nil { - t.Fatalf("error during decode: %s", err) - } - encoded, err := EncodeBuf(object, nil) - if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) - } - if decoded != object { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(decoded), decoded) - t.FailNow() - } -} - -func TestStrRuHelloWorld(t *testing.T) { - object := "привет мир" - binstring := bytes.Join([][]byte{mustHexDec("D3"), []byte("привет мир")}, nil) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != nil { - t.Fatalf("error during decode: %s", err) - } - encoded, err := EncodeBuf(object, nil) - if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) - } - if decoded != object { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(decoded), decoded) - t.FailNow() - } -} - -func TestStrLen62(t *testing.T) { - object := strings.Repeat("a", 62) - binstring := mustHexDec( - strings.Join([]string{"FD01", strings.Repeat("61", 62)}, ""), - ) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != nil { - t.Fatalf("error during decode: %s", err) - } - encoded, err := EncodeBuf(object, nil) - if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) - } - if decoded != object { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(decoded), decoded) - t.FailNow() - } -} - -func TestStrLen318(t *testing.T) { - object := strings.Repeat("a", 318) - binstring := mustHexDec( - strings.Join([]string{"FE0001", strings.Repeat("61", 318)}, ""), - ) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != nil { - t.Fatalf("error during decode: %s", err) - } - encoded, err := EncodeBuf(object, nil) - if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected binstring %s, got %s", hex.EncodeToString(binstring), hex.EncodeToString(encoded)) - } - if decoded != object { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(decoded), decoded) - t.FailNow() - } -} - -func TestStrLen65853(t *testing.T) { - object := strings.Repeat("a", 65853) - binstring := mustHexDec( - strings.Join([]string{"FF0000000000000000", strings.Repeat("61", 65853)}, ""), - ) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != nil { - t.Fatalf("error during decode: %s", err) - } - encoded, err := EncodeBuf(object, nil) - if err != nil { - t.Fatalf("error during encode: %s", err) - } - if !bytes.Equal(encoded, binstring) { - t.Logf("expected binstring to begin with %s, got %s", hex.EncodeToString(binstring)[:40], hex.EncodeToString(encoded)[:40]) - t.Fail() - } - if decoded != object { - t.Logf("expected type %s, value %s", reflect.TypeOf(object), object) - t.Logf("got type %s, value %s", reflect.TypeOf(decoded), decoded) - t.FailNow() - } -} - -func TestStrThrowsWhenNullByteInUTF8(t *testing.T) { - binstring := []byte("\xC5he\x00\x01\x02") - _, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != ErrBadUTF8 { - t.Fatalf("expected ErrBadUTF8, got %v", err) - } -} - -func TestStrOkWhenNullByteInUTF8AndUTF8CheckDisabled(t *testing.T) { - binstring := []byte("\xC5he\xe2\x82\x28") - _, err := NewDecoderFromBytes(binstring, &DecodeOpts{DisableUTF8Check: true}).Decode() - if err != nil { - t.Fatalf("error during decode: %v", err) - } -} - -func TestStrThrowsWhenInvalid2BytesInUTF8(t *testing.T) { - f := func(x, y int) bool { - binstring := bytes.Join([][]byte{[]byte("\xC2"), invalidUTF8_2Byte(x, y)}, nil) - _, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != ErrBadUTF8 { - t.Logf("expected ErrBadUTF8, got %v", err) - return false - } - return true - } - if err := quick.Check(f, &quick.Config{ - Values: func(v []reflect.Value, r *mrand.Rand) { - v[0] = reflect.ValueOf(r.Intn(1 << 5)) - v[1] = reflect.ValueOf(r.Intn(1 << 5)) - }, - }); err != nil { - t.Fatal(err) - } -} - -func TestStrOkWhenInvalid2BytesInUTF8AndUTF8CheckDisabled(t *testing.T) { - f := func(x, y int) bool { - _, err := NewDecoderFromBytes(bytes.Join([][]byte{[]byte("\xC2"), invalidUTF8_2Byte(x, y)}, nil), &DecodeOpts{DisableUTF8Check: true}).Decode() - if err != nil { - t.Logf("error during decode: %v", err) - return false - } - return true - } - if err := quick.Check(f, &quick.Config{ - Values: func(v []reflect.Value, r *mrand.Rand) { - v[0] = reflect.ValueOf(r.Intn(1 << 5)) - v[1] = reflect.ValueOf(r.Intn(1 << 5)) - }, - }); err != nil { - t.Fatal(err) - } -} - -func TestStrThrowsWhenInvalid3BytesInUTF8(t *testing.T) { - f := func(x, y, z int) bool { - binstring := bytes.Join([][]byte{[]byte("\xC3"), invalidUTF8_3Byte(x, y, z)}, nil) - _, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != ErrBadUTF8 { - t.Logf("expected ErrBadUTF8, got %v", err) - return false - } - return true - } - if err := quick.Check(f, &quick.Config{ - Values: func(v []reflect.Value, r *mrand.Rand) { - v[0] = reflect.ValueOf(r.Intn(1 << 4)) - v[1] = reflect.ValueOf(r.Intn(1 << 6)) - v[2] = reflect.ValueOf(r.Intn(1 << 6)) - }, - }); err != nil { - t.Fatal(err) - } -} - -func TestStrOkWhenInvalid3BytesInUTF8AndUTF8CheckDisabled(t *testing.T) { - f := func(x, y, z int) bool { - binstring := bytes.Join([][]byte{[]byte("\xC3"), invalidUTF8_3Byte(x, y, z)}, nil) - _, err := NewDecoderFromBytes(binstring, &DecodeOpts{DisableUTF8Check: true}).Decode() - if err != nil { - t.Logf("error during decode: %v", err) - return false - } - return true - } - if err := quick.Check(f, &quick.Config{ - Values: func(v []reflect.Value, r *mrand.Rand) { - v[0] = reflect.ValueOf(r.Intn(1 << 4)) - v[1] = reflect.ValueOf(r.Intn(1 << 6)) - v[2] = reflect.ValueOf(r.Intn(1 << 6)) - }, - }); err != nil { - t.Fatal(err) - } -} - -func TestStrThrowsWhenNotEnoughData(t *testing.T) { - binstring := []byte("\xC5he") - _, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %v", err) - } -} - -func TestStrThrowsWhenNotEnoughDataForLength8(t *testing.T) { - binstring := []byte("\xC5he") - _, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %v", err) - } -} - -func TestStrThrowsWhenNotEnoughDataForLength16(t *testing.T) { - binstring := []byte("\xC5he") - _, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %v", err) - } -} - -func TestThrowsWhenNotEnoughDataForLength64(t *testing.T) { - binstring := []byte("\xC5he") - _, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != io.ErrUnexpectedEOF { - t.Fatalf("expected io.ErrUnexpectedEOF, got %v", err) - } -} - -func TestStrThrowsWhenStringTooLong(t *testing.T) { - f := func(str string, y uint8) bool { - if str == "" { - return true - } - y = y % uint8(len(str)) - if y == 0 { - return true - } - encoded, _ := EncodeBuf(str, nil) - decoder := NewDecoderFromBytes(encoded, &DecodeOpts{MaxStrLen: int64(len(str) - int(y))}) - _, err := decoder.Decode() - if err != ErrLenTooBig { - t.Logf("expected ErrLenTooBig, got %v", err) - return false - } - return true - } - if err := quick.Check(f, nil); err != nil { - t.Fatal(err) - } -} - -func TestStrOkWhenMaxStrLenSet(t *testing.T) { - f := func(str string, y uint8) bool { - encoded, err := EncodeBuf(str, nil) - if err != nil { - return false - } - decoder := NewDecoderFromBytes(encoded, &DecodeOpts{MaxStrLen: int64(len(str) + int(y))}) - decoded, err := decoder.Decode() - if err != nil { - return false - } - if str != decoded.(string) { - t.Logf("Expected <%s, %s>", reflect.TypeOf(str), str) - t.Logf("Instead <%s, %s>", reflect.TypeOf(decoded), decoded) - return false - } - return true - } - if err := quick.Check(f, nil); err != nil { - t.Fatal(err) - } -} - -func TestStrSymmetric(t *testing.T) { - f := func(str string) bool { - encoded, err := EncodeBuf(str, nil) - if err != nil { - return false - } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() - if err != nil { - return false - } - if str != decoded.(string) { - t.Logf("Expected <%s, %s>", reflect.TypeOf(str), str) - t.Logf("Instead <%s, %s>", reflect.TypeOf(decoded), decoded) - return false - } - return true - } - if err := quick.Check(f, nil); err != nil { - t.Fatal(err) - } -} diff --git a/go/tai_test.go b/go/tai_test.go index ca533b1..92b9182 100644 --- a/go/tai_test.go +++ b/go/tai_test.go @@ -1,5 +1,6 @@ // GoKEKS -- Go KEKS codec implementation // Copyright (C) 2024-2025 Anton Rudenko +// Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as @@ -17,265 +18,466 @@ package keks import ( "bytes" + "io" + "strings" "testing" "testing/quick" "time" + + "go.cypherpunks.su/keks/be" + "go.cypherpunks.su/tai64n/v4" ) -func TestTai64LargeNumberOfSeconds(t *testing.T) { - binstring := bytes.Join([][]byte{ - mustHexDec("18"), - mustHexDec("7000000065195F65"), - }, nil) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != nil { - t.Fatalf("error during decode: %s", err) +const hex1G = "3B9ACA00" // one billion + +func TestTAINotEnoughData(t *testing.T) { + _, err := NewDecoderFromBytes(mustHexDec( + "18"+strings.Repeat("0", 2*8-2)), nil).Decode() + if err != io.ErrUnexpectedEOF { + t.Fatal(err) } - if err != nil { - t.Fatalf("error during encode: %s", err) +} + +func TestTAINNotEnoughData(t *testing.T) { + _, err := NewDecoderFromBytes(mustHexDec( + "19"+strings.Repeat("0", 2*12-2)), nil).Decode() + if err != io.ErrUnexpectedEOF { + t.Fatal(err) } - t.Log(decoded) } -func TestTai64NLargeNumberOfSeconds(t *testing.T) { - binstring := bytes.Join([][]byte{ - mustHexDec("19"), - mustHexDec("7000000065195F65"), - mustHexDec("3B9AC9FF"), - }, nil) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != nil { - t.Fatalf("error during decode: %s", err) +func TestTAINANotEnoughData(t *testing.T) { + _, err := NewDecoderFromBytes(mustHexDec( + "1A"+strings.Repeat("0", 2*16-2)), nil).Decode() + if err != io.ErrUnexpectedEOF { + t.Fatal(err) } +} + +func TestTAILargeNumberOfSeconds(t *testing.T) { + _, err := NewDecoderFromBytes(mustHexDec( + "18"+"7000000065195F65"), nil).Decode() if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - t.Log(decoded) } -func TestTai64NALargeNumberOfSeconds(t *testing.T) { - binstring := bytes.Join([][]byte{ - mustHexDec("1A"), - mustHexDec("7000000065195F66"), - mustHexDec("3B9AC9FF"), - mustHexDec("3B9AC9FF"), - }, nil) - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestTAINLargeNumberOfSeconds(t *testing.T) { + _, err := NewDecoderFromBytes(mustHexDec( + "19"+"7000000065195F65"+"00010000"), nil).Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } +} + +func TestTAINALargeNumberOfSeconds(t *testing.T) { + _, err := NewDecoderFromBytes(mustHexDec( + "1A"+"7000000065195F65"+"00010000"+"00010000"), nil).Decode() if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - t.Log(decoded) } -func TestTaiThrowsWhenMsbIsSet(t *testing.T) { - binstring := bytes.Join([][]byte{ - mustHexDec("18"), - mustHexDec("8000000065195F65"), - }, nil) - _, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != ErrTaiReserved { - t.Fatalf("expected 'reserved TAI64 value is in use', got %v", err) +func TestTAIMsbIsSet(t *testing.T) { + _, err := NewDecoderFromBytes(mustHexDec( + "18"+"8000000065195F65"), nil).Decode() + if err != ErrTAIReserved { + t.Fatal(err) + } +} + +func TestTAINMsbIsSet(t *testing.T) { + _, err := NewDecoderFromBytes(mustHexDec( + "19"+"8000000065195F65"+"00010000"), nil).Decode() + if err != ErrTAIReserved { + t.Fatal(err) + } +} + +func TestTAINAMsbIsSet(t *testing.T) { + _, err := NewDecoderFromBytes(mustHexDec( + "19"+"8000000065195F65"+"00010000"+"00010000"), nil).Decode() + if err != ErrTAIReserved { + t.Fatal(err) } } -func TestTai64NThrowsWhenTooManyNanosecs(t *testing.T) { - binstring := bytes.Join([][]byte{ - mustHexDec("19"), - mustHexDec("4000000000000000"), - mustHexDec("3B9ACA00"), - }, nil) - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestTAINTooManyNanosecs(t *testing.T) { + bin := mustHexDec("19" + "4000000000000000" + hex1G) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != ErrTooManyNsecs { - t.Fatalf("expected 'too many nanoseconds', got %v", err) + t.Fatal(err) } } -func TestTai64NThrowsWhenZeroNanoseconds(t *testing.T) { - binstring := bytes.Join([][]byte{ - mustHexDec("19"), - mustHexDec("4000000000000000"), - mustHexDec("00000000"), - }, nil) - _, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != ErrTaiNonMinimal { - t.Fatalf("expected 'non-minimal TAI64N', got %v", err) +func TestTAINATooManyNanosecs(t *testing.T) { + bin := mustHexDec("1A" + "4000000000000000" + hex1G + "00010000") + _, err := NewDecoderFromBytes(bin, nil).Decode() + if err != ErrTooManyNsecs { + t.Fatal(err) } } -func TestTai64NAThrowsWhenTooManyAttoseconds(t *testing.T) { - binstring := bytes.Join([][]byte{ - mustHexDec("1A"), - mustHexDec("4000000000000000"), - mustHexDec("00000000"), - mustHexDec("3B9ACA00"), - }, nil) - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestTAINATooManyAttosecs(t *testing.T) { + bin := mustHexDec("1A" + "4000000000000000" + "00010000" + hex1G) + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != ErrTooManyAsecs { - t.Fatalf("expected 'too many attoseconds', got %v", err) + t.Fatal(err) } } -func TestTai64NAThrowsWhenZeroAttoseconds(t *testing.T) { - binstring := bytes.Join([][]byte{ - mustHexDec("1A"), - mustHexDec("4000000000000000"), - mustHexDec("00000000"), - mustHexDec("00000000"), - }, nil) - _, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != ErrTaiNonMinimal { - t.Fatalf("expected 'non-minimal TAI64NA', got %v", err) +func TestTAINZeroNanosecs(t *testing.T) { + bin := mustHexDec("19" + "4000000000000000" + "00000000") + _, err := NewDecoderFromBytes(bin, nil).Decode() + if err != ErrTAINonMinimal { + t.Fatal(err) } } -func TestTai64NAZeroNanosecondsOk(t *testing.T) { - binstring := bytes.Join([][]byte{ - mustHexDec("1A"), - mustHexDec("4000000000000000"), - mustHexDec("00000000"), - mustHexDec("00000001"), - }, nil) - _, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestTAINAZeroNanosecsOk(t *testing.T) { + bin := mustHexDec("1A" + "4000000000000000" + "00000000" + "00000001") + _, err := NewDecoderFromBytes(bin, nil).Decode() if err != nil { - t.Fatalf("expected no error, got %v", err) + t.Fatal(err) } } -func TestTai64NAThrowsWhenMsbIsSet(t *testing.T) { - binstring := bytes.Join([][]byte{ - mustHexDec("1A"), - mustHexDec("8000000065195F65"), - mustHexDec("00000001"), - mustHexDec("00000001")}, nil) - _, err := NewDecoderFromBytes(binstring, nil).Decode() - if err != ErrTaiReserved { - t.Fatalf("expected 'reserved TAI64 value is in use', got %v", err) +func TestTAINAZeroAttosecs(t *testing.T) { + bin := mustHexDec("1A" + "4000000000000000" + "00000000" + "00000000") + _, err := NewDecoderFromBytes(bin, nil).Decode() + if err != ErrTAINonMinimal { + t.Fatal(err) } } -func TestTai19700101(t *testing.T) { - binstring := mustHexDec("18400000000000000A") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestTAI19700101(t *testing.T) { + decoded, err := NewDecoderFromBytes(mustHexDec( + "18400000000000000A"), nil).Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - if err != nil { - t.Fatalf("error during decode: %v", err) + casted, ok := decoded.(time.Time) + if !ok { + t.Fatal("failed to cast") } - expected := time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC) - decodedTime := decoded.(time.Time) - if !decodedTime.Equal(expected) { - t.Fatalf("expected %v, got %v", expected, decoded) + if !casted.Equal(time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)) { + t.Fatal("casted differs") } } -func TestTai19920602(t *testing.T) { - binstring := mustHexDec("18400000002A2B2C2D") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestTAI19920602(t *testing.T) { + decoded, err := NewDecoderFromBytes(mustHexDec( + "18400000002A2B2C2D"), nil).Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - decodedTime := decoded.(time.Time) - if err != nil { - t.Fatalf("error during decode: %v", err) + casted, ok := decoded.(time.Time) + if !ok { + t.Fatal("failed to cast") } - expected := time.Date(1992, 6, 2, 8, 6, 43, 0, time.UTC) - if !decodedTime.Equal(expected) { - t.Fatalf("expected %v, got %v", expected, decoded) + if !casted.Equal(time.Date(1992, 6, 2, 8, 6, 43, 0, time.UTC)) { + t.Fatal("casted differs") } } -func TestTai19971003(t *testing.T) { - binstring := mustHexDec("184000000034353637") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestTAI19971003(t *testing.T) { + decoded, err := NewDecoderFromBytes(mustHexDec( + "184000000034353637"), nil).Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - decodedTime := decoded.(time.Time) - if err != nil { - t.Fatalf("error during decode: %v", err) + casted, ok := decoded.(time.Time) + if !ok { + t.Fatal("failed to cast") } - expected := time.Date(1997, 10, 3, 18, 14, 48, 0, time.UTC) - if !decodedTime.Equal(expected) { - t.Fatalf("expected %v, got %v", expected, decoded) + if !casted.Equal(time.Date(1997, 10, 3, 18, 14, 48, 0, time.UTC)) { + t.Fatal("casted differs") } } -func TestTai20161231(t *testing.T) { - binstring := mustHexDec("1840000000586846A3") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestTAI20161231(t *testing.T) { + decoded, err := NewDecoderFromBytes(mustHexDec( + "1840000000586846A3"), nil).Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - decodedTime := decoded.(time.Time) - if err != nil { - t.Fatalf("error during decode: %v", err) + casted, ok := decoded.(time.Time) + if !ok { + t.Fatal("failed to cast") } - expected := time.Date(2016, 12, 31, 23, 59, 59, 0, time.UTC) - if !decodedTime.Equal(expected) { - t.Fatalf("expected %v, got %v", expected, decoded) + if !casted.Equal(time.Date(2016, 12, 31, 23, 59, 59, 0, time.UTC)) { + t.Fatal("casted differs") } } -func TestTai20170101(t *testing.T) { - binstring := mustHexDec("1840000000586846A5") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestTAI20170101(t *testing.T) { + decoded, err := NewDecoderFromBytes(mustHexDec( + "1840000000586846A5"), nil).Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - decodedTime := decoded.(time.Time) - if err != nil { - t.Fatalf("error during decode: %v", err) + casted, ok := decoded.(time.Time) + if !ok { + t.Fatal("failed to cast") } - expected := time.Date(2017, 1, 1, 0, 0, 0, 0, time.UTC) - if !decodedTime.Equal(expected) { - t.Fatalf("expected %v, got %v", expected, decoded) + if !casted.Equal(time.Date(2017, 1, 1, 0, 0, 0, 0, time.UTC)) { + t.Fatal("casted differs") } } -func TestTai20241120(t *testing.T) { - binstring := mustHexDec("1940000000673DD3E136F11FE0") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() +func TestTAI20241120(t *testing.T) { + decoded, err := NewDecoderFromBytes(mustHexDec( + "1940000000673DD3E136F11FE0"), nil).Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - decodedTime := decoded.(time.Time) - if err != nil { - t.Fatalf("error during decode: %v", err) + casted, ok := decoded.(time.Time) + if !ok { + t.Fatal("failed to cast") } - expected := time.Date(2024, 11, 20, 12, 19, 8, 921772000, time.UTC) - if !decodedTime.Equal(expected) { - t.Fatalf("expected %v, got %v", expected, decoded) + if !casted.Equal(time.Date(2024, 11, 20, 12, 19, 8, 921772000, time.UTC)) { + t.Fatal("casted differs") } } -func TestTaiSymmetric(t *testing.T) { - f := func(a, b int64) bool { - x := time.Unix(a, b) - if a > 1<<62-1 { +func TestTAISymmetric(t *testing.T) { + f := func(secs int64) bool { + if (secs > (1<<62)-1) || (secs < -(1 << 62)) { return true } - if a < -1<<62 { - return true + tm := time.Unix(secs, 0) + encoded, err := EncodeBuf(tm, nil) + if err != nil { + t.Fatal(err) } - encoded, err := EncodeBuf(x, nil) + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Logf("error during encode: %s", err) + t.Fatal(err) + } + casted, ok := decoded.(time.Time) + if !ok { + t.Fatal("failed to cast") + } + if !casted.Equal(tm) { return false } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + if !bytes.Equal(decoder.B, Junk) { + return false + } + decoder = NewDecoderFromBytes(append(encoded, Junk...), &DecodeOpts{ + LeaveTAI: true, + }) + decoded, err = decoder.Decode() if err != nil { - t.Logf("error during decode: %s", err) + t.Fatal(err) + } + casted, ok = decoded.(time.Time) + if !ok { + t.Fatal("failed to cast") + } + { + tai, isLeap := tai64n.Leapsecs.Sub(casted) + if isLeap { + return false + } + if !tai.Equal(tm) { + return false + } + if !bytes.Equal(decoder.B, Junk) { + return false + } + { + var encoded2 []byte + encoded2, err = EncodeBuf(casted, nil) + if err != nil { + t.Fatal(err) + } + if bytes.Equal(encoded, encoded2) { + return false + } + encoded2, err = EncodeBuf(casted, &EncodeOpts{LeaveTAI: true}) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(encoded, encoded2) { + return false + } + } + } + decoder = NewDecoderFromBytes(append(encoded, Junk...), &DecodeOpts{ + LeaveTAI64: true, + }) + decoded, err = decoder.Decode() + if err != nil { + t.Fatal(err) + } + { + tai, ok := decoded.(*tai64n.TAI64) + if !ok { + t.Fatal("failed to cast") + } + if !bytes.Equal(encoded[1:], tai[:]) { + return false + } + var raw []byte + raw, err = EncodeBuf(tai, nil) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(raw, encoded) { + return false + } + } + return bytes.Equal(decoder.B, Junk) + } + if err := quick.Check(f, nil); err != nil { + t.Fatal(err) + } +} + +func TestTAINSymmetric(t *testing.T) { + f := func(secs int64, nsecs uint32) bool { + if (secs > (1<<62)-1) || (secs < -(1 << 62)) { + return true + } + nsecs %= 1000 + if nsecs == 0 { + return true + } + tm := time.Unix(secs, int64(nsecs)) + encoded, err := EncodeBuf(tm, nil) + if err != nil { + t.Fatal(err) + } + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() + if err != nil { + t.Fatal(err) + } + casted, ok := decoded.(time.Time) + if !ok { + t.Fatal("failed to cast") + } + if !casted.Equal(tm) { + return false + } + if !bytes.Equal(decoder.B, Junk) { return false } - udecoded, ok := decoded.(time.Time) + decoder = NewDecoderFromBytes(append(encoded, Junk...), &DecodeOpts{ + LeaveTAI: true, + }) + decoded, err = decoder.Decode() + if err != nil { + t.Fatal(err) + } + casted, ok = decoded.(time.Time) if !ok { + t.Fatal("failed to cast") + } + { + tai, isLeap := tai64n.Leapsecs.Sub(casted) + if isLeap { + return false + } + if !tai.Equal(tm) { + return false + } + if !bytes.Equal(decoder.B, Junk) { + return false + } + { + var encoded2 []byte + encoded2, err = EncodeBuf(casted, nil) + if err != nil { + t.Fatal(err) + } + if bytes.Equal(encoded, encoded2) { + return false + } + encoded2, err = EncodeBuf(casted, &EncodeOpts{LeaveTAI: true}) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(encoded, encoded2) { + return false + } + } + } + decoder = NewDecoderFromBytes(append(encoded, Junk...), &DecodeOpts{ + LeaveTAI64: true, + }) + decoded, err = decoder.Decode() + if err != nil { + t.Fatal(err) + } + { + tai, ok := decoded.(*tai64n.TAI64N) + if !ok { + t.Fatal("failed to cast") + } + if !bytes.Equal(encoded[1:], tai[:]) { + return false + } + var raw []byte + raw, err = EncodeBuf(tai, nil) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(raw, encoded) { + return false + } + } + return bytes.Equal(decoder.B, Junk) + } + if err := quick.Check(f, nil); err != nil { + t.Fatal(err) + } +} + +func TestTAINASymmetric(t *testing.T) { + f := func(secs int64, nsecs, asecs uint32) bool { + if (secs > (1<<62)-1) || (secs < -(1 << 62)) { + return true + } + nsecs %= 1000 + asecs %= 1000 + if asecs == 0 { + return true + } + secs += tai64n.Base + encoded := make([]byte, 1+tai64n.TAI64NASize) + encoded[0] = byte(AtomTAI64NA) + be.Put(encoded[1:1+8], uint64(secs)) + be.Put(encoded[1+8:1+8+4], uint64(nsecs)) + be.Put(encoded[1+8+4:1+8+4+4], uint64(asecs)) + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() + if err != nil { + t.Fatal(err) + } + casted, ok := decoded.(*tai64n.TAI64NA) + if !ok { + t.Fatal("failed to cast") + } + if !bytes.Equal(casted[:], encoded[1:]) { return false } - return x.Equal(udecoded) + if !bytes.Equal(decoder.B, Junk) { + return false + } + { + var raw []byte + raw, err = EncodeBuf(casted, nil) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(raw, encoded) { + return false + } + } + return true } if err := quick.Check(f, nil); err != nil { t.Fatal(err) diff --git a/go/uuid_test.go b/go/uuid_test.go index 9dd3fc3..fc14c91 100644 --- a/go/uuid_test.go +++ b/go/uuid_test.go @@ -1,5 +1,6 @@ // GoKEKS -- Go KEKS codec implementation // Copyright (C) 2024-2025 Anton Rudenko +// Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as @@ -17,7 +18,7 @@ package keks import ( "bytes" - "reflect" + "io" "testing" "testing/quick" @@ -25,50 +26,59 @@ import ( ) func TestUUIDEncodeDecode(t *testing.T) { - object, _ := uuid.Parse("12345678-1234-5678-1234-567812345678") - binstring := mustHexDec("0412345678123456781234567812345678") - decoded, err := NewDecoderFromBytes(binstring, nil).Decode() + obj := uuid.MustParse("12345678-1234-5678-1234-567812345678") + bin := mustHexDec("0412345678123456781234567812345678") + decoder := NewDecoderFromBytes(append(bin, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during decode: %s", err) + t.Fatal(err) } - if err != nil { - t.Fatalf("error during encode: %s", err) + casted, ok := decoded.(uuid.UUID) + if !ok { + t.Fatal("failed to cast") } - if decoded != object { - t.Fatalf("expected %v, got %v", object, decoded) + if casted != obj { + t.Fatal("casted differs") } - encoded, err := EncodeBuf(object, nil) + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") + } + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) + t.Fatal(err) } - if !bytes.Equal(encoded, binstring) { - t.Fatalf("expected %v, got %v", binstring, encoded) + if !bytes.Equal(encoded, bin) { + t.Fatal("encoded differs") + } +} + +func TestUUIDNotEnoughData(t *testing.T) { + bin := mustHexDec("0412345678123456781234567812345678") + _, err := NewDecoderFromBytes(bin[:len(bin)-4], nil).Decode() + if err != io.ErrUnexpectedEOF { + t.Fatal(err) } } func TestUUIDSymmetric(t *testing.T) { - f := func(object uuid.UUID) bool { - encoded, err := EncodeBuf(object, nil) + f := func(obj uuid.UUID) bool { + encoded, err := EncodeBuf(obj, nil) if err != nil { - t.Fatalf("error during encode: %s", err) - return false + t.Fatal(err) } - decoded, err := NewDecoderFromBytes(encoded, nil).Decode() + decoder := NewDecoderFromBytes(append(encoded, Junk...), nil) + decoded, err := decoder.Decode() if err != nil { - t.Fatalf("error during encode: %s", err) - return false + t.Fatal(err) } - udecoded, ok := decoded.(uuid.UUID) + casted, ok := decoded.(uuid.UUID) if !ok { - t.Fatalf("failed to cast to uuid.UUID") - return false + t.Fatal("failed to cast") } - if object != udecoded { - t.Logf("expected <%s, %d>", reflect.TypeOf(object), object) - t.Logf("instead <%s, %d>", reflect.TypeOf(udecoded), udecoded) - return false + if !bytes.Equal(decoder.B, Junk) { + t.Fatal("tail differs") } - return true + return casted == obj } if err := quick.Check(f, nil); err != nil { t.Fatal(err) diff --git a/py3/tests/test_int.py b/py3/tests/test_int.py index 3c0bc56..2237e68 100644 --- a/py3/tests/test_int.py +++ b/py3/tests/test_int.py @@ -116,7 +116,7 @@ class TestInt(TestCase): loads(bytes.fromhex("0C8301")) self.assertEqual(err.exception.n, 2) - def test_throws_when_unminimal_int(self) -> None: + def test_throws_when_nonminimal_int(self) -> None: with self.assertRaises(DecodeError) as err: encoded: bytes = bytes.fromhex("0C81007B") loads(encoded) diff --git a/py3/tests/test_map.py b/py3/tests/test_map.py index 379a941..7b98eb3 100644 --- a/py3/tests/test_map.py +++ b/py3/tests/test_map.py @@ -121,14 +121,7 @@ class TestMap(TestCase): self.assertEqual(str(err.exception), "map keys can not be empty") def test_throws_when_decoding_empty_str_as_key(self): - encoded = b"".join(( - bytes.fromhex("09"), - bytes.fromhex("C0"), - bytes.fromhex("0C8101"), - bytes.fromhex("C4"), b"key1", - bytes.fromhex("C6"), b"value1", - bytes.fromhex("00"), - )) + encoded = bytes.fromhex("09" + "C0" + "C0" + "00") with self.assertRaises(DecodeError) as err: decoded, tail = loads(encoded) self.assertEqual(str(err.exception), "empty key") diff --git a/py3/tests/test_str.py b/py3/tests/test_str.py index 7edcfe5..a37edcf 100644 --- a/py3/tests/test_str.py +++ b/py3/tests/test_str.py @@ -109,7 +109,7 @@ class TestStr(TestCase): self.assertSequenceEqual(decoded, s) self.assertSequenceEqual(tail, junk) - def test_throws_when_null_byte_in_utf(self) -> None: + def test_throws_when_null_byte_in_utf8(self) -> None: with self.assertRaises(DecodeError) as err: result, tail = loads(b"\xc5he\x00\x01\x02") self.assertEqual(str(err.exception), "null byte in UTF-8")