feat: Consolidate and enhance tests for enchantrix and trix packages

This commit consolidates and enhances the tests for the `enchantrix` and `trix` packages, moving them into the `tdd/` directory to improve test coverage and organization.

- Consolidates existing tests from `pkg/enchantrix/` and `pkg/trix/` into new, more comprehensive test suites in `tdd/enchantrix/` and `tdd/trix/` respectively.
- Expands the test suites to include more "Bad" and "Ugly" scenarios.
- Deletes the original test files from `pkg/enchantrix/` and `pkg/trix/` to avoid redundancy.
- Organizes the `tdd/` directory with subdirectories for each package to prevent Go package conflicts.
This commit is contained in:
google-labs-jules[bot] 2025-11-02 17:41:44 +00:00
parent 8cf1df9495
commit 0e50aee481
7 changed files with 262 additions and 218 deletions

View file

@ -1,19 +0,0 @@
package enchantrix_test
import (
"testing"
"github.com/Snider/Enchantrix/pkg/enchantrix"
"github.com/stretchr/testify/assert"
)
func TestTransmute(t *testing.T) {
data := []byte("hello")
sigils := []enchantrix.Sigil{
&enchantrix.ReverseSigil{},
&enchantrix.HexSigil{},
}
result, err := enchantrix.Transmute(data, sigils)
assert.NoError(t, err)
assert.Equal(t, "6f6c6c6568", string(result))
}

View file

@ -1,32 +0,0 @@
package enchantrix_test
import (
"testing"
"github.com/Snider/Enchantrix/pkg/enchantrix"
"github.com/stretchr/testify/assert"
)
func TestNewSigil(t *testing.T) {
t.Run("ValidSigils", func(t *testing.T) {
validNames := []string{
"reverse", "hex", "base64", "gzip", "json", "json-indent",
"md4", "md5", "sha1", "sha224", "sha256", "sha384", "sha512",
"ripemd160", "sha3-224", "sha3-256", "sha3-384", "sha3-512",
"sha512-224", "sha512-256", "blake2s-256", "blake2b-256",
"blake2b-384", "blake2b-512",
}
for _, name := range validNames {
sigil, err := enchantrix.NewSigil(name)
assert.NoError(t, err)
assert.NotNil(t, sigil)
}
})
t.Run("InvalidSigil", func(t *testing.T) {
sigil, err := enchantrix.NewSigil("invalid-sigil-name")
assert.Error(t, err)
assert.Nil(t, sigil)
assert.Contains(t, err.Error(), "unknown sigil name")
})
}

View file

@ -1,78 +0,0 @@
package enchantrix_test
import (
"crypto"
"encoding/hex"
"testing"
"github.com/Snider/Enchantrix/pkg/enchantrix"
"github.com/stretchr/testify/assert"
)
func TestReverseSigil(t *testing.T) {
s := &enchantrix.ReverseSigil{}
data := []byte("hello")
reversed, err := s.In(data)
assert.NoError(t, err)
assert.Equal(t, "olleh", string(reversed))
original, err := s.Out(reversed)
assert.NoError(t, err)
assert.Equal(t, "hello", string(original))
}
func TestHexSigil(t *testing.T) {
s := &enchantrix.HexSigil{}
data := []byte("hello")
encoded, err := s.In(data)
assert.NoError(t, err)
assert.Equal(t, "68656c6c6f", string(encoded))
decoded, err := s.Out(encoded)
assert.NoError(t, err)
assert.Equal(t, "hello", string(decoded))
}
func TestBase64Sigil(t *testing.T) {
s := &enchantrix.Base64Sigil{}
data := []byte("hello")
encoded, err := s.In(data)
assert.NoError(t, err)
assert.Equal(t, "aGVsbG8=", string(encoded))
decoded, err := s.Out(encoded)
assert.NoError(t, err)
assert.Equal(t, "hello", string(decoded))
}
func TestGzipSigil(t *testing.T) {
s := &enchantrix.GzipSigil{}
data := []byte("hello")
compressed, err := s.In(data)
assert.NoError(t, err)
assert.NotEqual(t, data, compressed)
decompressed, err := s.Out(compressed)
assert.NoError(t, err)
assert.Equal(t, "hello", string(decompressed))
}
func TestJSONSigil(t *testing.T) {
s := &enchantrix.JSONSigil{Indent: true}
data := []byte(`{"hello":"world"}`)
indented, err := s.In(data)
assert.NoError(t, err)
assert.Equal(t, "{\n \"hello\": \"world\"\n}", string(indented))
s.Indent = false
compacted, err := s.In(indented)
assert.NoError(t, err)
assert.Equal(t, `{"hello":"world"}`, string(compacted))
}
func TestHashSigil(t *testing.T) {
s := enchantrix.NewHashSigil(crypto.SHA256)
data := []byte("hello")
hashed, err := s.In(data)
assert.NoError(t, err)
expectedHash := "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
assert.Equal(t, expectedHash, hex.EncodeToString(hashed))
unhashed, err := s.Out(hashed)
assert.NoError(t, err)
assert.Equal(t, hashed, unhashed)
}

View file

@ -1,34 +0,0 @@
package trix
import (
"testing"
)
func FuzzDecode(f *testing.F) {
// Seed with a valid encoded Trix object
validTrix := &Trix{
Header: map[string]interface{}{"content_type": "text/plain"},
Payload: []byte("hello world"),
}
validEncoded, _ := Encode(validTrix, "FUZZ")
f.Add(validEncoded)
// Seed with the corrupted header length from the ugly test
var buf []byte
buf = append(buf, []byte("UGLY")...)
buf = append(buf, byte(Version))
buf = append(buf, []byte{0, 0, 3, 232}...) // BigEndian representation of 1000
buf = append(buf, []byte("{}")...)
buf = append(buf, []byte("payload")...)
f.Add(buf)
// Seed with a short, invalid input
f.Add([]byte("short"))
f.Fuzz(func(t *testing.T, data []byte) {
// The fuzzer will generate random data here.
// We just need to call our function and make sure it doesn't panic.
// The fuzzer will report any crashes as failures.
_, _ = Decode(data, "FUZZ")
})
}

View file

@ -0,0 +1,159 @@
package enchantrix_test
import (
"crypto"
"encoding/hex"
"errors"
"testing"
"github.com/Snider/Enchantrix/pkg/enchantrix"
"github.com/stretchr/testify/assert"
)
// --- Transmute Tests ---
func TestTransmute_Good(t *testing.T) {
data := []byte("hello")
sigils := []enchantrix.Sigil{
&enchantrix.ReverseSigil{},
&enchantrix.HexSigil{},
}
result, err := enchantrix.Transmute(data, sigils)
assert.NoError(t, err)
assert.Equal(t, "6f6c6c6568", string(result))
}
type errorSigil struct{}
func (s *errorSigil) In(data []byte) ([]byte, error) {
return nil, errors.New("sigil error")
}
func (s *errorSigil) Out(data []byte) ([]byte, error) {
return nil, errors.New("sigil error")
}
func TestTransmute_Bad(t *testing.T) {
data := []byte("hello")
sigils := []enchantrix.Sigil{
&enchantrix.ReverseSigil{},
&errorSigil{},
}
_, err := enchantrix.Transmute(data, sigils)
assert.Error(t, err)
}
// --- Factory Tests ---
func TestNewSigil_Good(t *testing.T) {
validNames := []string{
"reverse", "hex", "base64", "gzip", "json", "json-indent",
"md4", "md5", "sha1", "sha224", "sha256", "sha384", "sha512",
"ripemd160", "sha3-224", "sha3-256", "sha3-384", "sha3-512",
"sha512-224", "sha512-256", "blake2s-256", "blake2b-256",
"blake2b-384", "blake2b-512",
}
for _, name := range validNames {
sigil, err := enchantrix.NewSigil(name)
assert.NoError(t, err, "Failed to create sigil: %s", name)
assert.NotNil(t, sigil, "Sigil should not be nil for name: %s", name)
}
}
func TestNewSigil_Bad(t *testing.T) {
sigil, err := enchantrix.NewSigil("invalid-sigil-name")
assert.Error(t, err)
assert.Nil(t, sigil)
assert.Contains(t, err.Error(), "unknown sigil name")
}
// --- Sigil Tests ---
func TestReverseSigil(t *testing.T) {
s := &enchantrix.ReverseSigil{}
data := []byte("hello")
reversed, err := s.In(data)
assert.NoError(t, err)
assert.Equal(t, "olleh", string(reversed))
original, err := s.Out(reversed)
assert.NoError(t, err)
assert.Equal(t, "hello", string(original))
// Ugly - empty string
empty := []byte("")
reversedEmpty, err := s.In(empty)
assert.NoError(t, err)
assert.Equal(t, "", string(reversedEmpty))
}
func TestHexSigil(t *testing.T) {
s := &enchantrix.HexSigil{}
data := []byte("hello")
encoded, err := s.In(data)
assert.NoError(t, err)
assert.Equal(t, "68656c6c6f", string(encoded))
decoded, err := s.Out(encoded)
assert.NoError(t, err)
assert.Equal(t, "hello", string(decoded))
// Bad - invalid hex string
_, err = s.Out([]byte("not hex"))
assert.Error(t, err)
}
func TestBase64Sigil(t *testing.T) {
s := &enchantrix.Base64Sigil{}
data := []byte("hello")
encoded, err := s.In(data)
assert.NoError(t, err)
assert.Equal(t, "aGVsbG8=", string(encoded))
decoded, err := s.Out(encoded)
assert.NoError(t, err)
assert.Equal(t, "hello", string(decoded))
// Bad - invalid base64 string
_, err = s.Out([]byte("not base64"))
assert.Error(t, err)
}
func TestGzipSigil(t *testing.T) {
s := &enchantrix.GzipSigil{}
data := []byte("hello")
compressed, err := s.In(data)
assert.NoError(t, err)
assert.NotEqual(t, data, compressed)
decompressed, err := s.Out(compressed)
assert.NoError(t, err)
assert.Equal(t, "hello", string(decompressed))
// Bad - invalid gzip data
_, err = s.Out([]byte("not gzip"))
assert.Error(t, err)
}
func TestJSONSigil(t *testing.T) {
s := &enchantrix.JSONSigil{Indent: true}
data := []byte(`{"hello":"world"}`)
indented, err := s.In(data)
assert.NoError(t, err)
assert.Equal(t, "{\n \"hello\": \"world\"\n}", string(indented))
s.Indent = false
compacted, err := s.In(indented)
assert.NoError(t, err)
assert.Equal(t, `{"hello":"world"}`, string(compacted))
// Bad - invalid json
_, err = s.In([]byte("not json"))
assert.Error(t, err)
}
func TestHashSigil(t *testing.T) {
s := enchantrix.NewHashSigil(crypto.SHA256)
data := []byte("hello")
hashed, err := s.In(data)
assert.NoError(t, err)
expectedHash := "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
assert.Equal(t, expectedHash, hex.EncodeToString(hashed))
unhashed, err := s.Out(hashed)
assert.NoError(t, err)
assert.Equal(t, hashed, unhashed) // Out is a no-op
}

View file

@ -1,4 +1,4 @@
package trix
package trix_test
import (
"io"
@ -6,6 +6,7 @@ import (
"testing"
"github.com/Snider/Enchantrix/pkg/crypt"
"github.com/Snider/Enchantrix/pkg/trix"
"github.com/stretchr/testify/assert"
)
@ -18,37 +19,37 @@ func TestTrixEncodeDecode_Good(t *testing.T) {
"created_at": "2025-10-30T12:00:00Z",
}
payload := []byte("This is a secret message.")
trix := &Trix{Header: header, Payload: payload}
trixOb := &trix.Trix{Header: header, Payload: payload}
magicNumber := "TRIX"
encoded, err := Encode(trix, magicNumber)
encoded, err := trix.Encode(trixOb, magicNumber)
assert.NoError(t, err)
decoded, err := Decode(encoded, magicNumber)
decoded, err := trix.Decode(encoded, magicNumber)
assert.NoError(t, err)
assert.True(t, reflect.DeepEqual(trix.Header, decoded.Header))
assert.Equal(t, trix.Payload, decoded.Payload)
assert.True(t, reflect.DeepEqual(trixOb.Header, decoded.Header))
assert.Equal(t, trixOb.Payload, decoded.Payload)
}
// TestTrixEncodeDecode_Bad tests expected failure scenarios with well-formed but invalid inputs.
func TestTrixEncodeDecode_Bad(t *testing.T) {
t.Run("MismatchedMagicNumber", func(t *testing.T) {
trix := &Trix{Header: map[string]interface{}{}, Payload: []byte("payload")}
encoded, err := Encode(trix, "GOOD")
trixOb := &trix.Trix{Header: map[string]interface{}{}, Payload: []byte("payload")}
encoded, err := trix.Encode(trixOb, "GOOD")
assert.NoError(t, err)
_, err = Decode(encoded, "BAD!")
_, err = trix.Decode(encoded, "BAD!")
assert.Error(t, err)
assert.Contains(t, err.Error(), "invalid magic number")
})
t.Run("InvalidMagicNumberLength", func(t *testing.T) {
trix := &Trix{Header: map[string]interface{}{}, Payload: []byte("payload")}
_, err := Encode(trix, "TOOLONG")
trixOb := &trix.Trix{Header: map[string]interface{}{}, Payload: []byte("payload")}
_, err := trix.Encode(trixOb, "TOOLONG")
assert.EqualError(t, err, "trix: magic number must be 4 bytes long")
_, err = Decode([]byte{}, "SHORT")
_, err = trix.Decode([]byte{}, "SHORT")
assert.EqualError(t, err, "trix: magic number must be 4 bytes long")
})
@ -57,11 +58,21 @@ func TestTrixEncodeDecode_Bad(t *testing.T) {
header := map[string]interface{}{
"unsupported": make(chan int), // Channels cannot be JSON-encoded
}
trix := &Trix{Header: header, Payload: []byte("payload")}
_, err := Encode(trix, "TRIX")
trixOb := &trix.Trix{Header: header, Payload: []byte("payload")}
_, err := trix.Encode(trixOb, "TRIX")
assert.Error(t, err)
assert.Contains(t, err.Error(), "json: unsupported type")
})
t.Run("HeaderTooLarge", func(t *testing.T) {
data := make([]byte, trix.MaxHeaderSize+10)
trixOb := &trix.Trix{
Header: map[string]interface{}{"large": string(data)},
Payload: []byte("payload"),
}
_, err := trix.Encode(trixOb, "TRIX")
assert.NoError(t, err)
})
}
// TestTrixEncodeDecode_Ugly tests malicious or malformed inputs designed to cause crashes or panics.
@ -71,43 +82,40 @@ func TestTrixEncodeDecode_Ugly(t *testing.T) {
t.Run("CorruptedHeaderLength", func(t *testing.T) {
// Manually construct a byte slice where the header length is larger than the actual data.
var buf []byte
buf = append(buf, []byte(magicNumber)...) // Magic Number
buf = append(buf, byte(Version)) // Version
// Header length of 1000, but the header is only 2 bytes long.
buf = append(buf, []byte{0, 0, 3, 232}...) // BigEndian representation of 1000
buf = append(buf, []byte("{}")...) // A minimal valid JSON header
buf = append(buf, []byte(magicNumber)...) // Magic Number
buf = append(buf, byte(trix.Version)) // Version
buf = append(buf, []byte{0, 0, 3, 232}...) // BigEndian representation of 1000
buf = append(buf, []byte("{}")...) // A minimal valid JSON header
buf = append(buf, []byte("payload")...)
_, err := Decode(buf, magicNumber)
_, err := trix.Decode(buf, magicNumber)
assert.Error(t, err)
assert.Equal(t, err, io.ErrUnexpectedEOF)
})
t.Run("DataTooShort", func(t *testing.T) {
// Data is too short to contain even the magic number.
data := []byte("BAD")
_, err := Decode(data, magicNumber)
_, err := trix.Decode(data, magicNumber)
assert.Error(t, err)
})
t.Run("EmptyPayload", func(t *testing.T) {
data := []byte{}
_, err := Decode(data, magicNumber)
_, err := trix.Decode(data, magicNumber)
assert.Error(t, err)
})
t.Run("FuzzedJSON", func(t *testing.T) {
// A header that is technically valid but contains unexpected types.
header := map[string]interface{}{
"payload": map[string]interface{}{"nested": 123},
}
payload := []byte("some data")
trix := &Trix{Header: header, Payload: payload}
trixOb := &trix.Trix{Header: header, Payload: payload}
encoded, err := Encode(trix, magicNumber)
encoded, err := trix.Encode(trixOb, magicNumber)
assert.NoError(t, err)
decoded, err := Decode(encoded, magicNumber)
decoded, err := trix.Decode(encoded, magicNumber)
assert.NoError(t, err)
assert.NotNil(t, decoded)
})
@ -117,86 +125,126 @@ func TestTrixEncodeDecode_Ugly(t *testing.T) {
func TestPackUnpack_Good(t *testing.T) {
originalPayload := []byte("hello world")
trix := &Trix{
Header: map[string]interface{}{},
Payload: originalPayload,
trixOb := &trix.Trix{
Header: map[string]interface{}{},
Payload: originalPayload,
InSigils: []string{"reverse", "reverse"}, // Double reverse should be original
}
err := trix.Pack()
err := trixOb.Pack()
assert.NoError(t, err)
assert.Equal(t, originalPayload, trix.Payload) // Should be back to the original
assert.Equal(t, originalPayload, trixOb.Payload)
err = trix.Unpack()
err = trixOb.Unpack()
assert.NoError(t, err)
assert.Equal(t, originalPayload, trix.Payload) // Should be back to the original again
assert.Equal(t, originalPayload, trixOb.Payload)
}
func TestPackUnpack_Bad(t *testing.T) {
trix := &Trix{
Header: map[string]interface{}{},
Payload: []byte("some data"),
trixOb := &trix.Trix{
Header: map[string]interface{}{},
Payload: []byte("some data"),
InSigils: []string{"reverse", "invalid-sigil-name"},
}
err := trix.Pack()
err := trixOb.Pack()
assert.Error(t, err)
assert.Contains(t, err.Error(), "unknown sigil name")
trixOb.InSigils = []string{"hex"}
trixOb.Payload = []byte("not hex")
err = trixOb.Unpack()
assert.Error(t, err)
}
func TestPackUnpack_Ugly(t *testing.T) {
trixOb := &trix.Trix{
Header: map[string]interface{}{},
Payload: nil, // Nil payload
InSigils: []string{"reverse"},
}
err := trixOb.Pack()
assert.NoError(t, err) // Should handle nil payload gracefully
err = trixOb.Unpack()
assert.NoError(t, err)
}
// --- Checksum Tests ---
func TestChecksum_Good(t *testing.T) {
trix := &Trix{
trixOb := &trix.Trix{
Header: map[string]interface{}{},
Payload: []byte("hello world"),
ChecksumAlgo: crypt.SHA256,
}
encoded, err := Encode(trix, "CHCK")
encoded, err := trix.Encode(trixOb, "CHCK")
assert.NoError(t, err)
decoded, err := Decode(encoded, "CHCK")
decoded, err := trix.Decode(encoded, "CHCK")
assert.NoError(t, err)
assert.Equal(t, trix.Payload, decoded.Payload)
assert.Equal(t, trixOb.Payload, decoded.Payload)
}
func TestChecksum_Bad(t *testing.T) {
trix := &Trix{
trixOb := &trix.Trix{
Header: map[string]interface{}{},
Payload: []byte("hello world"),
ChecksumAlgo: crypt.SHA256,
}
encoded, err := Encode(trix, "CHCK")
encoded, err := trix.Encode(trixOb, "CHCK")
assert.NoError(t, err)
// Tamper with the payload
encoded[len(encoded)-1] = 0
encoded[len(encoded)-1] = 0 // Tamper with the payload
_, err = Decode(encoded, "CHCK")
_, err = trix.Decode(encoded, "CHCK")
assert.Error(t, err)
assert.Equal(t, ErrChecksumMismatch, err)
assert.Equal(t, trix.ErrChecksumMismatch, err)
}
func TestChecksum_Ugly(t *testing.T) {
t.Run("MissingAlgoInHeader", func(t *testing.T) {
trix := &Trix{
trixOb := &trix.Trix{
Header: map[string]interface{}{},
Payload: []byte("hello world"),
ChecksumAlgo: crypt.SHA256,
}
encoded, err := Encode(trix, "UGLY")
encoded, err := trix.Encode(trixOb, "UGLY")
assert.NoError(t, err)
// Manually decode to tamper with the header
decoded, err := Decode(encoded, "UGLY")
decoded, err := trix.Decode(encoded, "UGLY")
assert.NoError(t, err)
delete(decoded.Header, "checksum_algo")
// Re-encode with the tampered header
tamperedEncoded, err := Encode(decoded, "UGLY")
tamperedEncoded, err := trix.Encode(decoded, "UGLY")
assert.NoError(t, err)
_, err = Decode(tamperedEncoded, "UGLY")
_, err = trix.Decode(tamperedEncoded, "UGLY")
assert.Error(t, err)
})
}
// --- Fuzz Tests ---
func FuzzDecode(f *testing.F) {
validTrix := &trix.Trix{
Header: map[string]interface{}{"content_type": "text/plain"},
Payload: []byte("hello world"),
}
validEncoded, _ := trix.Encode(validTrix, "FUZZ")
f.Add(validEncoded)
var buf []byte
buf = append(buf, []byte("UGLY")...)
buf = append(buf, byte(trix.Version))
buf = append(buf, []byte{0, 0, 3, 232}...)
buf = append(buf, []byte("{}")...)
buf = append(buf, []byte("payload")...)
f.Add(buf)
f.Add([]byte("short"))
f.Fuzz(func(t *testing.T, data []byte) {
_, _ = trix.Decode(data, "FUZZ")
})
}