feat: Add Good, Bad, and Ugly tests

This commit refactors the test suites for the `crypt` and `enchantrix` packages to follow the "Good, Bad, Ugly" testing methodology.

- `_Good` tests cover the ideal "happy path" scenarios.
- `_Bad` tests cover expected failure scenarios with well-formed but invalid inputs.
- `_Ugly` tests cover malicious or malformed inputs designed to cause crashes or panics.

This change improves test coverage and ensures that the codebase is more robust and resilient to unexpected inputs.
This commit is contained in:
google-labs-jules[bot] 2025-11-13 21:27:38 +00:00
parent d649e9e69e
commit e112ec363d
6 changed files with 246 additions and 18 deletions

View file

@ -3,6 +3,7 @@ package crypt
import (
"crypto/md5"
"crypto/sha1"
"errors"
"crypto/sha256"
"crypto/sha512"
"encoding/binary"
@ -217,5 +218,8 @@ func (s *Service) VerifyPGP(publicKey, data, signature []byte) error {
// SymmetricallyEncryptPGP encrypts data with a passphrase.
func (s *Service) SymmetricallyEncryptPGP(passphrase, data []byte) ([]byte, error) {
s.ensurePGP()
if len(passphrase) == 0 {
return nil, errors.New("passphrase cannot be empty")
}
return s.pgp.SymmetricallyEncrypt(passphrase, data)
}

View file

@ -6,8 +6,28 @@ import (
"github.com/stretchr/testify/assert"
)
func TestEnsureRSA(t *testing.T) {
// TestEnsureRSA_Good tests that the RSA service is initialized correctly.
func TestEnsureRSA_Good(t *testing.T) {
s := &Service{}
s.ensureRSA()
assert.NotNil(t, s.rsa)
}
// TestEnsureRSA_Bad tests that calling ensureRSA multiple times does not change the RSA service.
func TestEnsureRSA_Bad(t *testing.T) {
s := &Service{}
s.ensureRSA()
rsa1 := s.rsa
s.ensureRSA()
rsa2 := s.rsa
assert.Same(t, rsa1, rsa2)
}
// TestEnsureRSA_Ugly tests that ensureRSA works correctly on a service with a pre-initialized RSA service.
func TestEnsureRSA_Ugly(t *testing.T) {
s := NewService() // NewService initializes the RSA service
rsa1 := s.rsa
s.ensureRSA()
rsa2 := s.rsa
assert.Same(t, rsa1, rsa2)
}

View file

@ -155,6 +155,63 @@ func TestPGP_Good(t *testing.T) {
assert.NotNil(t, ciphertext)
}
func TestPGP_Bad(t *testing.T) {
// Generate two key pairs
pubKey1, privKey1, err := service.GeneratePGPKeyPair("test1", "test1@test.com", "")
assert.NoError(t, err)
pubKey2, privKey2, err := service.GeneratePGPKeyPair("test2", "test2@test.com", "")
assert.NoError(t, err)
message := []byte("secret message")
// Test decryption with the wrong key
ciphertext, err := service.EncryptPGP(pubKey1, message)
assert.NoError(t, err)
// This should fail because we are using the wrong private key.
_, err = service.DecryptPGP(privKey2, ciphertext) // Intentionally using wrong key
assert.Error(t, err)
// Test verification with the wrong key
signature, err := service.SignPGP(privKey1, message)
assert.NoError(t, err)
err = service.VerifyPGP(pubKey2, message, signature)
assert.Error(t, err)
// Test verification with a tampered message
tamperedMessage := []byte("tampered message")
err = service.VerifyPGP(pubKey1, tamperedMessage, signature)
assert.Error(t, err)
}
func TestPGP_Ugly(t *testing.T) {
// Test with malformed keys
_, err := service.EncryptPGP([]byte("not a real key"), []byte("message"))
assert.Error(t, err)
_, err = service.DecryptPGP([]byte("not a real key"), []byte("message"))
assert.Error(t, err)
_, err = service.SignPGP([]byte("not a real key"), []byte("message"))
assert.Error(t, err)
err = service.VerifyPGP([]byte("not a real key"), []byte("message"), []byte("not a real signature"))
assert.Error(t, err)
// Test with empty message
pubKey, privKey, err := service.GeneratePGPKeyPair("test", "test@test.com", "")
assert.NoError(t, err)
message := []byte("")
ciphertext, err := service.EncryptPGP(pubKey, message)
assert.NoError(t, err)
plaintext, err := service.DecryptPGP(privKey, ciphertext, )
assert.NoError(t, err)
assert.Equal(t, message, plaintext)
// Test symmetric encryption with empty passphrase
_, err = service.SymmetricallyEncryptPGP([]byte(""), message)
assert.Error(t, err)
}
// --- IsHashAlgo Tests ---
func TestIsHashAlgo_Good(t *testing.T) {

View file

@ -40,6 +40,21 @@ func TestTransmute_Bad(t *testing.T) {
assert.Error(t, err)
}
func TestTransmute_Ugly(t *testing.T) {
// Test with nil data
_, err := enchantrix.Transmute(nil, []enchantrix.Sigil{&enchantrix.ReverseSigil{}})
assert.NoError(t, err)
// Test with nil sigils
_, err = enchantrix.Transmute([]byte("hello"), nil)
assert.NoError(t, err)
// Test with no sigils
result, err := enchantrix.Transmute([]byte("hello"), []enchantrix.Sigil{})
assert.NoError(t, err)
assert.Equal(t, "hello", string(result))
}
// --- Factory Tests ---
func TestNewSigil_Good(t *testing.T) {
@ -63,3 +78,20 @@ func TestNewSigil_Bad(t *testing.T) {
assert.Nil(t, sigil)
assert.Contains(t, err.Error(), "unknown sigil name")
}
func TestNewSigil_Ugly(t *testing.T) {
// Test with empty string
sigil, err := enchantrix.NewSigil("")
assert.Error(t, err)
assert.Nil(t, sigil)
// Test with whitespace
sigil, err = enchantrix.NewSigil(" ")
assert.Error(t, err)
assert.Nil(t, sigil)
// Test with non-printable characters
sigil, err = enchantrix.NewSigil("\x00\x01\x02")
assert.Error(t, err)
assert.Nil(t, sigil)
}

View file

@ -26,6 +26,9 @@ type ReverseSigil struct{}
// In reverses the bytes of the data.
func (s *ReverseSigil) In(data []byte) ([]byte, error) {
if data == nil {
return nil, nil
}
reversed := make([]byte, len(data))
for i, j := 0, len(data)-1; i < len(data); i, j = i+1, j-1 {
reversed[i] = data[j]
@ -43,6 +46,9 @@ type HexSigil struct{}
// In encodes the data to hexadecimal.
func (s *HexSigil) In(data []byte) ([]byte, error) {
if data == nil {
return nil, nil
}
dst := make([]byte, hex.EncodedLen(len(data)))
hex.Encode(dst, data)
return dst, nil
@ -50,6 +56,9 @@ func (s *HexSigil) In(data []byte) ([]byte, error) {
// Out decodes the data from hexadecimal.
func (s *HexSigil) Out(data []byte) ([]byte, error) {
if data == nil {
return nil, nil
}
dst := make([]byte, hex.DecodedLen(len(data)))
_, err := hex.Decode(dst, data)
return dst, err
@ -60,6 +69,9 @@ type Base64Sigil struct{}
// In encodes the data to base64.
func (s *Base64Sigil) In(data []byte) ([]byte, error) {
if data == nil {
return nil, nil
}
dst := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
base64.StdEncoding.Encode(dst, data)
return dst, nil
@ -67,6 +79,9 @@ func (s *Base64Sigil) In(data []byte) ([]byte, error) {
// Out decodes the data from base64.
func (s *Base64Sigil) Out(data []byte) ([]byte, error) {
if data == nil {
return nil, nil
}
dst := make([]byte, base64.StdEncoding.DecodedLen(len(data)))
n, err := base64.StdEncoding.Decode(dst, data)
return dst[:n], err
@ -79,6 +94,9 @@ type GzipSigil struct {
// In compresses the data using gzip.
func (s *GzipSigil) In(data []byte) ([]byte, error) {
if data == nil {
return nil, nil
}
var b bytes.Buffer
w := s.writer
if w == nil {
@ -96,6 +114,9 @@ func (s *GzipSigil) In(data []byte) ([]byte, error) {
// Out decompresses the data using gzip.
func (s *GzipSigil) Out(data []byte) ([]byte, error) {
if data == nil {
return nil, nil
}
r, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
return nil, err

View file

@ -28,7 +28,7 @@ func (m *failOnSecondWrite) Write(p []byte) (n int, err error) {
return len(p), nil
}
func TestReverseSigil(t *testing.T) {
func TestReverseSigil_Good(t *testing.T) {
s := &ReverseSigil{}
data := []byte("hello")
reversed, err := s.In(data)
@ -37,15 +37,23 @@ func TestReverseSigil(t *testing.T) {
original, err := s.Out(reversed)
assert.NoError(t, err)
assert.Equal(t, "hello", string(original))
}
// Ugly - empty string
func TestReverseSigil_Ugly(t *testing.T) {
s := &ReverseSigil{}
// Test with empty string
empty := []byte("")
reversedEmpty, err := s.In(empty)
assert.NoError(t, err)
assert.Equal(t, "", string(reversedEmpty))
// Test with nil
reversedNil, err := s.In(nil)
assert.NoError(t, err)
assert.Nil(t, reversedNil)
}
func TestHexSigil(t *testing.T) {
func TestHexSigil_Good(t *testing.T) {
s := &HexSigil{}
data := []byte("hello")
encoded, err := s.In(data)
@ -54,13 +62,29 @@ func TestHexSigil(t *testing.T) {
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"))
func TestHexSigil_Bad(t *testing.T) {
s := &HexSigil{}
_, err := s.Out([]byte("not hex"))
assert.Error(t, err)
}
func TestBase64Sigil(t *testing.T) {
func TestHexSigil_Ugly(t *testing.T) {
s := &HexSigil{}
// Test with empty string
empty := []byte("")
encodedEmpty, err := s.In(empty)
assert.NoError(t, err)
assert.Equal(t, "", string(encodedEmpty))
// Test with nil
encodedNil, err := s.In(nil)
assert.NoError(t, err)
assert.Nil(t, encodedNil)
}
func TestBase64Sigil_Good(t *testing.T) {
s := &Base64Sigil{}
data := []byte("hello")
encoded, err := s.In(data)
@ -69,13 +93,29 @@ func TestBase64Sigil(t *testing.T) {
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"))
func TestBase64Sigil_Bad(t *testing.T) {
s := &Base64Sigil{}
_, err := s.Out([]byte("not base64"))
assert.Error(t, err)
}
func TestGzipSigil(t *testing.T) {
func TestBase64Sigil_Ugly(t *testing.T) {
s := &Base64Sigil{}
// Test with empty string
empty := []byte("")
encodedEmpty, err := s.In(empty)
assert.NoError(t, err)
assert.Equal(t, "", string(encodedEmpty))
// Test with nil
encodedNil, err := s.In(nil)
assert.NoError(t, err)
assert.Nil(t, encodedNil)
}
func TestGzipSigil_Good(t *testing.T) {
s := &GzipSigil{}
data := []byte("hello")
compressed, err := s.In(data)
@ -84,9 +124,14 @@ func TestGzipSigil(t *testing.T) {
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"))
func TestGzipSigil_Bad(t *testing.T) {
s := &GzipSigil{}
data := []byte("hello")
// Test with invalid gzip data
_, err := s.Out([]byte("not gzip"))
assert.Error(t, err)
// Test writer error
@ -100,27 +145,60 @@ func TestGzipSigil(t *testing.T) {
assert.Error(t, err)
}
func TestJSONSigil(t *testing.T) {
func TestGzipSigil_Ugly(t *testing.T) {
s := &GzipSigil{}
// Test with empty string
empty := []byte("")
compressedEmpty, err := s.In(empty)
assert.NoError(t, err)
decompressedEmpty, err := s.Out(compressedEmpty)
assert.NoError(t, err)
assert.Equal(t, "", string(decompressedEmpty))
// Test with nil
compressedNil, err := s.In(nil)
assert.NoError(t, err)
decompressedNil, err := s.Out(compressedNil)
assert.NoError(t, err)
assert.Nil(t, decompressedNil)
}
func TestJSONSigil_Good(t *testing.T) {
s := &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)
// Out is a no-op, so it should return the data as-is
// Out is a no-op
outData, err := s.Out(data)
assert.NoError(t, err)
assert.Equal(t, data, outData)
}
func TestJSONSigil_Bad(t *testing.T) {
s := &JSONSigil{}
_, err := s.In([]byte("not json"))
assert.Error(t, err)
}
func TestJSONSigil_Ugly(t *testing.T) {
s := &JSONSigil{}
// Test with empty string
empty := []byte("")
_, err := s.In(empty)
assert.Error(t, err)
// Test with nil
_, err = s.In(nil)
assert.Error(t, err)
}
func TestHashSigils_Good(t *testing.T) {
// Using the input "hello" for all hash tests
data := []byte("hello")
@ -172,3 +250,19 @@ func TestHashSigil_Bad(t *testing.T) {
assert.Error(t, err)
assert.Contains(t, err.Error(), "hash algorithm not available")
}
func TestHashSigil_Ugly(t *testing.T) {
s, err := NewSigil("sha256")
assert.NoError(t, err)
// Test with empty string
empty := []byte("")
hashedEmpty, err := s.In(empty)
assert.NoError(t, err)
assert.NotEmpty(t, hashedEmpty)
// Test with nil
hashedNil, err := s.In(nil)
assert.NoError(t, err)
assert.NotEmpty(t, hashedNil)
}