Migrate package imports from next.orly.dev to new orly domain structure; add new varint and binary encoders with comprehensive tests; enhance existing tag and envelope implementations with additional methods, validations, and test coverage; introduce shared test.sh script for streamlined testing across modules.

This commit is contained in:
2025-08-31 16:52:24 +01:00
parent 94383f29e9
commit 91d95c6f1a
202 changed files with 12803 additions and 420 deletions

View File

@@ -0,0 +1,439 @@
package indexes
import (
"io"
"reflect"
"database.orly/indexes/types"
"interfaces.orly/codec"
"lol.mleku.dev/chk"
)
var counter int
func init() {
// Initialize the counter to ensure it starts from 0
counter = 0
}
func next() int { counter++; return counter - 1 }
type P struct {
val []byte
}
func NewPrefix(prf ...int) (p *P) {
if len(prf) > 0 {
prefix := Prefix(prf[0])
if prefix == "" {
panic("unknown prefix")
}
return &P{[]byte(prefix)}
} else {
return &P{[]byte{0, 0, 0}}
}
}
func (p *P) Bytes() (b []byte) { return p.val }
func (p *P) MarshalWrite(w io.Writer) (err error) {
_, err = w.Write(p.val)
return
}
func (p *P) UnmarshalRead(r io.Reader) (err error) {
// Allocate a buffer for val if it's nil or empty
if p.val == nil || len(p.val) == 0 {
p.val = make([]byte, 3) // Prefixes are 3 bytes
}
_, err = r.Read(p.val)
return
}
type I string
func (i I) Write(w io.Writer) (n int, err error) { return w.Write([]byte(i)) }
const (
EventPrefix = I("evt")
IdPrefix = I("eid")
FullIdPubkeyPrefix = I("fpc") // full id, pubkey, created at
CreatedAtPrefix = I("c--") // created at
KindPrefix = I("kc-") // kind, created at
PubkeyPrefix = I("pc-") // pubkey, created at
KindPubkeyPrefix = I("kpc") // kind, pubkey, created at
TagPrefix = I("tc-") // tag, created at
TagKindPrefix = I("tkc") // tag, kind, created at
TagPubkeyPrefix = I("tpc") // tag, pubkey, created at
TagKindPubkeyPrefix = I("tkp") // tag, kind, pubkey, created at
ExpirationPrefix = I("exp") // timestamp of expiration
VersionPrefix = I("ver") // database version number, for triggering reindexes when new keys are added (policy is add-only).
)
// Prefix returns the three byte human-readable prefixes that go in front of
// database indexes.
func Prefix(prf int) (i I) {
switch prf {
case Event:
return EventPrefix
case Id:
return IdPrefix
case FullIdPubkey:
return FullIdPubkeyPrefix
case CreatedAt:
return CreatedAtPrefix
case Kind:
return KindPrefix
case Pubkey:
return PubkeyPrefix
case KindPubkey:
return KindPubkeyPrefix
case Tag:
return TagPrefix
case TagKind:
return TagKindPrefix
case TagPubkey:
return TagPubkeyPrefix
case TagKindPubkey:
return TagKindPubkeyPrefix
case Expiration:
return ExpirationPrefix
case Version:
return VersionPrefix
}
return
}
func Identify(r io.Reader) (i int, err error) {
// this is here for completeness; however, searches don't need to identify
// this as they work via generated prefixes made using Prefix.
var b [3]byte
_, err = r.Read(b[:])
if err != nil {
i = -1
return
}
switch I(b[:]) {
case EventPrefix:
i = Event
case IdPrefix:
i = Id
case FullIdPubkeyPrefix:
i = FullIdPubkey
case CreatedAtPrefix:
i = CreatedAt
case KindPrefix:
i = Kind
case PubkeyPrefix:
i = Pubkey
case KindPubkeyPrefix:
i = KindPubkey
case TagPrefix:
i = Tag
case TagKindPrefix:
i = TagKind
case TagPubkeyPrefix:
i = TagPubkey
case TagKindPubkeyPrefix:
i = TagKindPubkey
case ExpirationPrefix:
i = Expiration
}
return
}
type Encs []codec.I
// T is a wrapper around an array of codec.I. The caller provides the Encs so
// they can then call the accessor methods of the codec.I implementation.
type T struct{ Encs }
// New creates a new indexes.T. The helper functions below have an encode and
// decode variant, the decode variant doesn't add the prefix encoder because it
// has been read by Identify or just is being read, and found because it was
// written for the prefix in the iteration.
func New(encoders ...codec.I) (i *T) { return &T{encoders} }
func (t *T) MarshalWrite(w io.Writer) (err error) {
for _, e := range t.Encs {
if e == nil || reflect.ValueOf(e).IsNil() {
// Skip nil encoders instead of returning early. This enables
// generating search prefixes.
continue
}
if err = e.MarshalWrite(w); chk.E(err) {
return
}
}
return
}
func (t *T) UnmarshalRead(r io.Reader) (err error) {
for _, e := range t.Encs {
if err = e.UnmarshalRead(r); chk.E(err) {
return
}
}
return
}
// Event is the whole event stored in binary format
//
// prefix|5 serial - event in binary format
var Event = next()
func EventVars() (ser *types.Uint40) { return new(types.Uint40) }
func EventEnc(ser *types.Uint40) (enc *T) {
return New(NewPrefix(Event), ser)
}
func EventDec(ser *types.Uint40) (enc *T) { return New(NewPrefix(), ser) }
// Id contains a truncated 8-byte hash of an event index. This is the secondary
// key of an event, the primary key is the serial found in the Event.
//
// 3 prefix|8 ID hash|5 serial
var Id = next()
func IdVars() (id *types.IdHash, ser *types.Uint40) {
return new(types.IdHash), new(types.Uint40)
}
func IdEnc(id *types.IdHash, ser *types.Uint40) (enc *T) {
return New(NewPrefix(Id), id, ser)
}
func IdDec(id *types.IdHash, ser *types.Uint40) (enc *T) {
return New(NewPrefix(), id, ser)
}
// FullIdPubkey is an index designed to enable sorting and filtering of
// results found via other indexes, without having to decode the event.
//
// 3 prefix|5 serial|32 ID|8 pubkey hash|8 timestamp
var FullIdPubkey = next()
func FullIdPubkeyVars() (
ser *types.Uint40, fid *types.Id, p *types.PubHash, ca *types.Uint64,
) {
return new(types.Uint40), new(types.Id), new(types.PubHash), new(types.Uint64)
}
func FullIdPubkeyEnc(
ser *types.Uint40, fid *types.Id, p *types.PubHash, ca *types.Uint64,
) (enc *T) {
return New(NewPrefix(FullIdPubkey), ser, fid, p, ca)
}
func FullIdPubkeyDec(
ser *types.Uint40, fid *types.Id, p *types.PubHash, ca *types.Uint64,
) (enc *T) {
return New(NewPrefix(), ser, fid, p, ca)
}
// CreatedAt is an index that allows search for the timestamp on the event.
//
// 3 prefix|8 timestamp|5 serial
var CreatedAt = next()
func CreatedAtVars() (ca *types.Uint64, ser *types.Uint40) {
return new(types.Uint64), new(types.Uint40)
}
func CreatedAtEnc(ca *types.Uint64, ser *types.Uint40) (enc *T) {
return New(NewPrefix(CreatedAt), ca, ser)
}
func CreatedAtDec(ca *types.Uint64, ser *types.Uint40) (enc *T) {
return New(NewPrefix(), ca, ser)
}
// Kind
//
// 3 prefix|2 kind|8 timestamp|5 serial
var Kind = next()
func KindVars() (ki *types.Uint16, ca *types.Uint64, ser *types.Uint40) {
return new(types.Uint16), new(types.Uint64), new(types.Uint40)
}
func KindEnc(ki *types.Uint16, ca *types.Uint64, ser *types.Uint40) (enc *T) {
return New(NewPrefix(Kind), ki, ca, ser)
}
func KindDec(ki *types.Uint16, ca *types.Uint64, ser *types.Uint40) (enc *T) {
return New(NewPrefix(), ki, ca, ser)
}
// Pubkey is a composite index that allows search by pubkey
// filtered by timestamp.
//
// 3 prefix|8 pubkey hash|8 timestamp|5 serial
var Pubkey = next()
func PubkeyVars() (p *types.PubHash, ca *types.Uint64, ser *types.Uint40) {
return new(types.PubHash), new(types.Uint64), new(types.Uint40)
}
func PubkeyEnc(p *types.PubHash, ca *types.Uint64, ser *types.Uint40) (enc *T) {
return New(NewPrefix(Pubkey), p, ca, ser)
}
func PubkeyDec(p *types.PubHash, ca *types.Uint64, ser *types.Uint40) (enc *T) {
return New(NewPrefix(), p, ca, ser)
}
// KindPubkey
//
// 3 prefix|2 kind|8 pubkey hash|8 timestamp|5 serial
var KindPubkey = next()
func KindPubkeyVars() (
ki *types.Uint16, p *types.PubHash, ca *types.Uint64, ser *types.Uint40,
) {
return new(types.Uint16), new(types.PubHash), new(types.Uint64), new(types.Uint40)
}
func KindPubkeyEnc(
ki *types.Uint16, p *types.PubHash, ca *types.Uint64, ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(KindPubkey), ki, p, ca, ser)
}
func KindPubkeyDec(
ki *types.Uint16, p *types.PubHash, ca *types.Uint64, ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(), ki, p, ca, ser)
}
// Tag allows searching for a tag and filter by timestamp.
//
// 3 prefix|1 key letter|8 value hash|8 timestamp|5 serial
var Tag = next()
func TagVars() (
k *types.Letter, v *types.Ident, ca *types.Uint64, ser *types.Uint40,
) {
return new(types.Letter), new(types.Ident), new(types.Uint64), new(types.Uint40)
}
func TagEnc(
k *types.Letter, v *types.Ident, ca *types.Uint64, ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(Tag), k, v, ca, ser)
}
func TagDec(
k *types.Letter, v *types.Ident, ca *types.Uint64, ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(), k, v, ca, ser)
}
// TagKind
//
// 3 prefix|1 key letter|8 value hash|2 kind|8 timestamp|5 serial
var TagKind = next()
func TagKindVars() (
k *types.Letter, v *types.Ident, ki *types.Uint16, ca *types.Uint64,
ser *types.Uint40,
) {
return new(types.Letter), new(types.Ident), new(types.Uint16), new(types.Uint64), new(types.Uint40)
}
func TagKindEnc(
k *types.Letter, v *types.Ident, ki *types.Uint16, ca *types.Uint64,
ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(TagKind), ki, k, v, ca, ser)
}
func TagKindDec(
k *types.Letter, v *types.Ident, ki *types.Uint16, ca *types.Uint64,
ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(), ki, k, v, ca, ser)
}
// TagPubkey allows searching for a pubkey, tag and timestamp.
//
// 3 prefix|1 key letter|8 value hash|8 pubkey hash|8 timestamp|5 serial
var TagPubkey = next()
func TagPubkeyVars() (
k *types.Letter, v *types.Ident, p *types.PubHash, ca *types.Uint64,
ser *types.Uint40,
) {
return new(types.Letter), new(types.Ident), new(types.PubHash), new(types.Uint64), new(types.Uint40)
}
func TagPubkeyEnc(
k *types.Letter, v *types.Ident, p *types.PubHash, ca *types.Uint64,
ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(TagPubkey), p, k, v, ca, ser)
}
func TagPubkeyDec(
k *types.Letter, v *types.Ident, p *types.PubHash, ca *types.Uint64,
ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(), p, k, v, ca, ser)
}
// TagKindPubkey
//
// 3 prefix|1 key letter|8 value hash|2 kind|8 pubkey hash|8 bytes timestamp|5 serial
var TagKindPubkey = next()
func TagKindPubkeyVars() (
k *types.Letter, v *types.Ident, ki *types.Uint16, p *types.PubHash,
ca *types.Uint64,
ser *types.Uint40,
) {
return new(types.Letter), new(types.Ident), new(types.Uint16), new(types.PubHash), new(types.Uint64), new(types.Uint40)
}
func TagKindPubkeyEnc(
k *types.Letter, v *types.Ident, ki *types.Uint16, p *types.PubHash,
ca *types.Uint64,
ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(TagKindPubkey), ki, p, k, v, ca, ser)
}
func TagKindPubkeyDec(
k *types.Letter, v *types.Ident, ki *types.Uint16, p *types.PubHash,
ca *types.Uint64,
ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(), ki, p, k, v, ca, ser)
}
// Expiration
//
// 3 prefix|8 timestamp|5 serial
var Expiration = next()
func ExpirationVars() (
exp *types.Uint64, ser *types.Uint40,
) {
return new(types.Uint64), new(types.Uint40)
}
func ExpirationEnc(
exp *types.Uint64, ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(Expiration), exp, ser)
}
func ExpirationDec(
exp *types.Uint64, ser *types.Uint40,
) (enc *T) {
return New(NewPrefix(), exp, ser)
}
// Version
//
// 3 prefix|4 version
var Version = next()
func VersionVars() (
ver *types.Uint32,
) {
return new(types.Uint32)
}
func VersionEnc(
ver *types.Uint32,
) (enc *T) {
return New(NewPrefix(Version), ver)
}
func VersionDec(
ver *types.Uint32,
) (enc *T) {
return New(NewPrefix(), ver)
}

View File

@@ -0,0 +1,981 @@
package indexes
import (
"bytes"
"io"
"testing"
"database.orly/indexes/types"
"lol.mleku.dev/chk"
"utils.orly"
)
// TestNewPrefix tests the NewPrefix function with and without arguments
func TestNewPrefix(t *testing.T) {
// Test with no arguments (default prefix)
defaultPrefix := NewPrefix()
if len(defaultPrefix.Bytes()) != 3 {
t.Errorf(
"Default prefix should be 3 bytes, got %d",
len(defaultPrefix.Bytes()),
)
}
// Test with a valid prefix index
validPrefix := NewPrefix(Event)
if string(validPrefix.Bytes()) != string(EventPrefix) {
t.Errorf("Expected prefix %q, got %q", EventPrefix, validPrefix.Bytes())
}
// Test with an invalid prefix index (should panic)
defer func() {
if r := recover(); r == nil {
t.Errorf("NewPrefix should panic with invalid prefix index")
}
}()
_ = NewPrefix(-1) // This should panic
}
// TestPrefixMethods tests the methods of the P struct
func TestPrefixMethods(t *testing.T) {
// Create a prefix
prefix := NewPrefix(Event)
// Test Bytes method
if !utils.FastEqual(prefix.Bytes(), []byte(EventPrefix)) {
t.Errorf(
"Bytes method returned %v, expected %v", prefix.Bytes(),
[]byte(EventPrefix),
)
}
// Test MarshalWrite method
buf := new(bytes.Buffer)
err := prefix.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
if !utils.FastEqual(buf.Bytes(), []byte(EventPrefix)) {
t.Errorf(
"MarshalWrite wrote %v, expected %v", buf.Bytes(),
[]byte(EventPrefix),
)
}
// Test UnmarshalRead method
newPrefix := &P{}
err = newPrefix.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
if !utils.FastEqual(newPrefix.Bytes(), []byte(EventPrefix)) {
t.Errorf(
"UnmarshalRead read %v, expected %v", newPrefix.Bytes(),
[]byte(EventPrefix),
)
}
}
// TestPrefixFunction tests the Prefix function
func TestPrefixFunction(t *testing.T) {
testCases := []struct {
name string
index int
expected I
}{
{"Event", Event, EventPrefix},
{"ID", Id, IdPrefix},
{"FullIdPubkey", FullIdPubkey, FullIdPubkeyPrefix},
{"Pubkey", Pubkey, PubkeyPrefix},
{"CreatedAt", CreatedAt, CreatedAtPrefix},
{"TagPubkey", TagPubkey, TagPubkeyPrefix},
{"Tag", Tag, TagPrefix},
{"Kind", Kind, KindPrefix},
{"KindPubkey", KindPubkey, KindPubkeyPrefix},
{"TagKind", TagKind, TagKindPrefix},
{
"TagKindPubkey", TagKindPubkey,
TagKindPubkeyPrefix,
},
{"Invalid", -1, ""},
}
for _, tc := range testCases {
t.Run(
tc.name, func(t *testing.T) {
result := Prefix(tc.index)
if result != tc.expected {
t.Errorf(
"Prefix(%d) = %q, expected %q", tc.index, result,
tc.expected,
)
}
},
)
}
}
// TestIdentify tests the Identify function
func TestIdentify(t *testing.T) {
testCases := []struct {
name string
prefix I
expected int
}{
{"Event", EventPrefix, Event},
{"ID", IdPrefix, Id},
{"FullIdPubkey", FullIdPubkeyPrefix, FullIdPubkey},
{"Pubkey", PubkeyPrefix, Pubkey},
{"CreatedAt", CreatedAtPrefix, CreatedAt},
{"TagPubkey", TagPubkeyPrefix, TagPubkey},
{"Tag", TagPrefix, Tag},
{"Kind", KindPrefix, Kind},
{"KindPubkey", KindPubkeyPrefix, KindPubkey},
{"TagKind", TagKindPrefix, TagKind},
{
"TagKindPubkey", TagKindPubkeyPrefix,
TagKindPubkey,
},
}
for _, tc := range testCases {
t.Run(
tc.name, func(t *testing.T) {
result, err := Identify(bytes.NewReader([]byte(tc.prefix)))
if chk.E(err) {
t.Fatalf("Identify failed: %v", err)
}
if result != tc.expected {
t.Errorf(
"Identify(%q) = %d, expected %d", tc.prefix, result,
tc.expected,
)
}
},
)
}
// Test with invalid data
t.Run(
"Invalid", func(t *testing.T) {
result, err := Identify(bytes.NewReader([]byte("xyz")))
if chk.E(err) {
t.Fatalf("Identify failed: %v", err)
}
if result != 0 {
t.Errorf(
"Identify with invalid prefix should return 0, got %d",
result,
)
}
},
)
// Test with error from reader
t.Run(
"ReaderError", func(t *testing.T) {
errReader := &errorReader{}
result, err := Identify(errReader)
if err == nil {
t.Errorf("Identify should return error with failing reader")
}
if result != -1 {
t.Errorf(
"Identify with reader error should return -1, got %d",
result,
)
}
},
)
}
// errorReader is a mock reader that always returns an error
type errorReader struct{}
func (e *errorReader) Read(p []byte) (n int, err error) {
return 0, io.ErrUnexpectedEOF
}
// TestTStruct tests the T struct and its methods
func TestTStruct(t *testing.T) {
// Create some test encoders
prefix := NewPrefix(Event)
ser := new(types.Uint40)
ser.Set(12345)
// Test New function
enc := New(prefix, ser)
if len(enc.Encs) != 2 {
t.Errorf("New should create T with 2 encoders, got %d", len(enc.Encs))
}
// Test MarshalWrite
buf := new(bytes.Buffer)
err := enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Test UnmarshalRead
dec := New(NewPrefix(), new(types.Uint40))
err = dec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded values
decodedPrefix := dec.Encs[0].(*P)
decodedSer := dec.Encs[1].(*types.Uint40)
if !utils.FastEqual(decodedPrefix.Bytes(), prefix.Bytes()) {
t.Errorf(
"Decoded prefix %v, expected %v", decodedPrefix.Bytes(),
prefix.Bytes(),
)
}
if decodedSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", decodedSer.Get(), ser.Get())
}
// Test with nil encoder
encWithNil := New(prefix, nil, ser)
buf.Reset()
err = encWithNil.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite with nil encoder failed: %v", err)
}
}
// TestEventFunctions tests the Event-related functions
func TestEventFunctions(t *testing.T) {
// Test EventVars
ser := EventVars()
if ser == nil {
t.Fatalf("EventVars should return non-nil *types.Uint40")
}
// Set a value
ser.Set(12345)
// Test EventEnc
enc := EventEnc(ser)
if len(enc.Encs) != 2 {
t.Errorf(
"EventEnc should create T with 2 encoders, got %d", len(enc.Encs),
)
}
// Test EventDec
dec := EventDec(ser)
if len(dec.Encs) != 2 {
t.Errorf(
"EventDec should create T with 2 encoders, got %d", len(dec.Encs),
)
}
// Test marshaling and unmarshaling
buf := new(bytes.Buffer)
err := enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Create new variables for decoding
newSer := new(types.Uint40)
newDec := EventDec(newSer)
err = newDec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded value
if newSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", newSer.Get(), ser.Get())
}
}
// TestIdFunctions tests the Id-related functions
func TestIdFunctions(t *testing.T) {
// Test IdVars
id, ser := IdVars()
if id == nil || ser == nil {
t.Fatalf("IdVars should return non-nil *types.IdHash and *types.Uint40")
}
// Set values
id.Set([]byte{1, 2, 3, 4, 5, 6, 7, 8})
ser.Set(12345)
// Test IdEnc
enc := IdEnc(id, ser)
if len(enc.Encs) != 3 {
t.Errorf("IdEnc should create T with 3 encoders, got %d", len(enc.Encs))
}
// Test IdDec
dec := IdDec(id, ser)
if len(dec.Encs) != 3 {
t.Errorf("IdDec should create T with 3 encoders, got %d", len(dec.Encs))
}
// Test marshaling and unmarshaling
buf := new(bytes.Buffer)
err := enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Create new variables for decoding
newId, newSer := IdVars()
newDec := IdDec(newId, newSer)
err = newDec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded values
if !utils.FastEqual(newId.Bytes(), id.Bytes()) {
t.Errorf("Decoded id %v, expected %v", newId.Bytes(), id.Bytes())
}
if newSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", newSer.Get(), ser.Get())
}
}
// TestIdPubkeyFunctions tests the FullIdPubkey-related functions
func TestIdPubkeyFunctions(t *testing.T) {
// Test FullIdPubkeyVars
ser, fid, p, ca := FullIdPubkeyVars()
if ser == nil || fid == nil || p == nil || ca == nil {
t.Fatalf("FullIdPubkeyVars should return non-nil values")
}
// Set values
ser.Set(12345)
err := fid.FromId(
[]byte{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
},
)
if chk.E(err) {
t.Fatalf("FromId failed: %v", err)
}
err = p.FromPubkey(
[]byte{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
},
)
if chk.E(err) {
t.Fatalf("FromPubkey failed: %v", err)
}
ca.Set(98765)
// Test FullIdPubkeyEnc
enc := FullIdPubkeyEnc(ser, fid, p, ca)
if len(enc.Encs) != 5 {
t.Errorf(
"FullIdPubkeyEnc should create T with 5 encoders, got %d",
len(enc.Encs),
)
}
// Test FullIdPubkeyDec
dec := FullIdPubkeyDec(ser, fid, p, ca)
if len(dec.Encs) != 5 {
t.Errorf(
"FullIdPubkeyDec should create T with 5 encoders, got %d",
len(dec.Encs),
)
}
// Test marshaling and unmarshaling
buf := new(bytes.Buffer)
err = enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Create new variables for decoding
newSer, newFid, newP, newCa := FullIdPubkeyVars()
newDec := FullIdPubkeyDec(newSer, newFid, newP, newCa)
err = newDec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded values
if newSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", newSer.Get(), ser.Get())
}
if !utils.FastEqual(newFid.Bytes(), fid.Bytes()) {
t.Errorf("Decoded id %v, expected %v", newFid.Bytes(), fid.Bytes())
}
if !utils.FastEqual(newP.Bytes(), p.Bytes()) {
t.Errorf("Decoded pubkey hash %v, expected %v", newP.Bytes(), p.Bytes())
}
if newCa.Get() != ca.Get() {
t.Errorf("Decoded created at %d, expected %d", newCa.Get(), ca.Get())
}
}
// TestCreatedAtFunctions tests the CreatedAt-related functions
func TestCreatedAtFunctions(t *testing.T) {
// Test CreatedAtVars
ca, ser := CreatedAtVars()
if ca == nil || ser == nil {
t.Fatalf("CreatedAtVars should return non-nil values")
}
// Set values
ca.Set(98765)
ser.Set(12345)
// Test CreatedAtEnc
enc := CreatedAtEnc(ca, ser)
if len(enc.Encs) != 3 {
t.Errorf(
"CreatedAtEnc should create T with 3 encoders, got %d",
len(enc.Encs),
)
}
// Test CreatedAtDec
dec := CreatedAtDec(ca, ser)
if len(dec.Encs) != 3 {
t.Errorf(
"CreatedAtDec should create T with 3 encoders, got %d",
len(dec.Encs),
)
}
// Test marshaling and unmarshaling
buf := new(bytes.Buffer)
err := enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Create new variables for decoding
newCa, newSer := CreatedAtVars()
newDec := CreatedAtDec(newCa, newSer)
err = newDec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded values
if newCa.Get() != ca.Get() {
t.Errorf("Decoded created at %d, expected %d", newCa.Get(), ca.Get())
}
if newSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", newSer.Get(), ser.Get())
}
}
// TestPubkeyFunctions tests the Pubkey-related functions
func TestPubkeyFunctions(t *testing.T) {
// Test PubkeyVars
p, ca, ser := PubkeyVars()
if p == nil || ca == nil || ser == nil {
t.Fatalf("PubkeyVars should return non-nil values")
}
// Set values
err := p.FromPubkey(
[]byte{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
},
)
if chk.E(err) {
t.Fatalf("FromPubkey failed: %v", err)
}
ca.Set(98765)
ser.Set(12345)
// Test PubkeyEnc
enc := PubkeyEnc(p, ca, ser)
if len(enc.Encs) != 4 {
t.Errorf(
"PubkeyEnc should create T with 4 encoders, got %d",
len(enc.Encs),
)
}
// Test PubkeyDec
dec := PubkeyDec(p, ca, ser)
if len(dec.Encs) != 4 {
t.Errorf(
"PubkeyDec should create T with 4 encoders, got %d",
len(dec.Encs),
)
}
// Test marshaling and unmarshaling
buf := new(bytes.Buffer)
err = enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Create new variables for decoding
newP, newCa, newSer := PubkeyVars()
newDec := PubkeyDec(newP, newCa, newSer)
err = newDec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded values
if !utils.FastEqual(newP.Bytes(), p.Bytes()) {
t.Errorf("Decoded pubkey hash %v, expected %v", newP.Bytes(), p.Bytes())
}
if newCa.Get() != ca.Get() {
t.Errorf("Decoded created at %d, expected %d", newCa.Get(), ca.Get())
}
if newSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", newSer.Get(), ser.Get())
}
}
// TestPubkeyTagFunctions tests the TagPubkey-related functions
func TestPubkeyTagFunctions(t *testing.T) {
// Test TagPubkeyVars
k, v, p, ca, ser := TagPubkeyVars()
if p == nil || k == nil || v == nil || ca == nil || ser == nil {
t.Fatalf("TagPubkeyVars should return non-nil values")
}
// Set values
err := p.FromPubkey(
[]byte{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
},
)
if chk.E(err) {
t.Fatalf("FromPubkey failed: %v", err)
}
k.Set('e')
v.FromIdent([]byte("test-value"))
if chk.E(err) {
t.Fatalf("FromIdent failed: %v", err)
}
ca.Set(98765)
ser.Set(12345)
// Test TagPubkeyEnc
enc := TagPubkeyEnc(k, v, p, ca, ser)
if len(enc.Encs) != 6 {
t.Errorf(
"TagPubkeyEnc should create T with 6 encoders, got %d",
len(enc.Encs),
)
}
// Test TagPubkeyDec
dec := TagPubkeyDec(k, v, p, ca, ser)
if len(dec.Encs) != 6 {
t.Errorf(
"TagPubkeyDec should create T with 6 encoders, got %d",
len(dec.Encs),
)
}
// Test marshaling and unmarshaling
buf := new(bytes.Buffer)
err = enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Create new variables for decoding
newK, newV, newP, newCa, newSer := TagPubkeyVars()
newDec := TagPubkeyDec(newK, newV, newP, newCa, newSer)
err = newDec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded values
if !utils.FastEqual(newP.Bytes(), p.Bytes()) {
t.Errorf("Decoded pubkey hash %v, expected %v", newP.Bytes(), p.Bytes())
}
if newK.Letter() != k.Letter() {
t.Errorf(
"Decoded key letter %c, expected %c", newK.Letter(), k.Letter(),
)
}
if !utils.FastEqual(newV.Bytes(), v.Bytes()) {
t.Errorf("Decoded value hash %v, expected %v", newV.Bytes(), v.Bytes())
}
if newCa.Get() != ca.Get() {
t.Errorf("Decoded created at %d, expected %d", newCa.Get(), ca.Get())
}
if newSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", newSer.Get(), ser.Get())
}
}
// TestTagFunctions tests the Tag-related functions
func TestTagFunctions(t *testing.T) {
var err error
// Test TagVars
k, v, ca, ser := TagVars()
if k == nil || v == nil || ca == nil || ser == nil {
t.Fatalf("TagVars should return non-nil values")
}
// Set values
k.Set('e')
v.FromIdent([]byte("test-value"))
if chk.E(err) {
t.Fatalf("FromIdent failed: %v", err)
}
ca.Set(98765)
ser.Set(12345)
// Test TagEnc
enc := TagEnc(k, v, ca, ser)
if len(enc.Encs) != 5 {
t.Errorf(
"TagEnc should create T with 5 encoders, got %d",
len(enc.Encs),
)
}
// Test TagDec
dec := TagDec(k, v, ca, ser)
if len(dec.Encs) != 5 {
t.Errorf(
"TagDec should create T with 5 encoders, got %d",
len(dec.Encs),
)
}
// Test marshaling and unmarshaling
buf := new(bytes.Buffer)
err = enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Create new variables for decoding
newK, newV, newCa, newSer := TagVars()
newDec := TagDec(newK, newV, newCa, newSer)
err = newDec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded values
if newK.Letter() != k.Letter() {
t.Errorf(
"Decoded key letter %c, expected %c", newK.Letter(), k.Letter(),
)
}
if !utils.FastEqual(newV.Bytes(), v.Bytes()) {
t.Errorf("Decoded value hash %v, expected %v", newV.Bytes(), v.Bytes())
}
if newCa.Get() != ca.Get() {
t.Errorf("Decoded created at %d, expected %d", newCa.Get(), ca.Get())
}
if newSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", newSer.Get(), ser.Get())
}
}
// TestKindFunctions tests the Kind-related functions
func TestKindFunctions(t *testing.T) {
// Test KindVars
ki, ca, ser := KindVars()
if ki == nil || ca == nil || ser == nil {
t.Fatalf("KindVars should return non-nil values")
}
// Set values
ki.Set(1234)
ca.Set(98765)
ser.Set(12345)
// Test KindEnc
enc := KindEnc(ki, ca, ser)
if len(enc.Encs) != 4 {
t.Errorf(
"KindEnc should create T with 4 encoders, got %d",
len(enc.Encs),
)
}
// Test KindDec
dec := KindDec(ki, ca, ser)
if len(dec.Encs) != 4 {
t.Errorf(
"KindDec should create T with 4 encoders, got %d",
len(dec.Encs),
)
}
// Test marshaling and unmarshaling
buf := new(bytes.Buffer)
err := enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Create new variables for decoding
newKi, newCa, newSer := KindVars()
newDec := KindDec(newKi, newCa, newSer)
err = newDec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded values
if newKi.Get() != ki.Get() {
t.Errorf("Decoded kind %d, expected %d", newKi.Get(), ki.Get())
}
if newCa.Get() != ca.Get() {
t.Errorf("Decoded created at %d, expected %d", newCa.Get(), ca.Get())
}
if newSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", newSer.Get(), ser.Get())
}
}
// TestKindTagFunctions tests the TagKind-related functions
func TestKindTagFunctions(t *testing.T) {
var err error
// Test TagKindVars
k, v, ki, ca, ser := TagKindVars()
if ki == nil || k == nil || v == nil || ca == nil || ser == nil {
t.Fatalf("TagKindVars should return non-nil values")
}
// Set values
ki.Set(1234)
k.Set('e')
v.FromIdent([]byte("test-value"))
if chk.E(err) {
t.Fatalf("FromIdent failed: %v", err)
}
ca.Set(98765)
ser.Set(12345)
// Test TagKindEnc
enc := TagKindEnc(k, v, ki, ca, ser)
if len(enc.Encs) != 6 {
t.Errorf(
"TagKindEnc should create T with 6 encoders, got %d",
len(enc.Encs),
)
}
// Test TagKindDec
dec := TagKindDec(k, v, ki, ca, ser)
if len(dec.Encs) != 6 {
t.Errorf(
"TagKindDec should create T with 6 encoders, got %d",
len(dec.Encs),
)
}
// Test marshaling and unmarshaling
buf := new(bytes.Buffer)
err = enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Create new variables for decoding
newK, newV, newKi, newCa, newSer := TagKindVars()
newDec := TagKindDec(newK, newV, newKi, newCa, newSer)
err = newDec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded values
if newKi.Get() != ki.Get() {
t.Errorf("Decoded kind %d, expected %d", newKi.Get(), ki.Get())
}
if newK.Letter() != k.Letter() {
t.Errorf(
"Decoded key letter %c, expected %c", newK.Letter(), k.Letter(),
)
}
if !utils.FastEqual(newV.Bytes(), v.Bytes()) {
t.Errorf("Decoded value hash %v, expected %v", newV.Bytes(), v.Bytes())
}
if newCa.Get() != ca.Get() {
t.Errorf("Decoded created at %d, expected %d", newCa.Get(), ca.Get())
}
if newSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", newSer.Get(), ser.Get())
}
}
// TestKindPubkeyFunctions tests the KindPubkey-related functions
func TestKindPubkeyFunctions(t *testing.T) {
// Test KindPubkeyVars
ki, p, ca, ser := KindPubkeyVars()
if ki == nil || p == nil || ca == nil || ser == nil {
t.Fatalf("KindPubkeyVars should return non-nil values")
}
// Set values
ki.Set(1234)
err := p.FromPubkey(
[]byte{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
},
)
if chk.E(err) {
t.Fatalf("FromPubkey failed: %v", err)
}
ca.Set(98765)
ser.Set(12345)
// Test KindPubkeyEnc
enc := KindPubkeyEnc(ki, p, ca, ser)
if len(enc.Encs) != 5 {
t.Errorf(
"KindPubkeyEnc should create T with 5 encoders, got %d",
len(enc.Encs),
)
}
// Test KindPubkeyDec
dec := KindPubkeyDec(ki, p, ca, ser)
if len(dec.Encs) != 5 {
t.Errorf(
"KindPubkeyDec should create T with 5 encoders, got %d",
len(dec.Encs),
)
}
// Test marshaling and unmarshaling
buf := new(bytes.Buffer)
err = enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Create new variables for decoding
newKi, newP, newCa, newSer := KindPubkeyVars()
newDec := KindPubkeyDec(newKi, newP, newCa, newSer)
err = newDec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded values
if newKi.Get() != ki.Get() {
t.Errorf("Decoded kind %d, expected %d", newKi.Get(), ki.Get())
}
if !utils.FastEqual(newP.Bytes(), p.Bytes()) {
t.Errorf("Decoded pubkey hash %v, expected %v", newP.Bytes(), p.Bytes())
}
if newCa.Get() != ca.Get() {
t.Errorf("Decoded created at %d, expected %d", newCa.Get(), ca.Get())
}
if newSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", newSer.Get(), ser.Get())
}
}
// TestKindPubkeyTagFunctions tests the TagKindPubkey-related functions
func TestKindPubkeyTagFunctions(t *testing.T) {
// Test TagKindPubkeyVars
k, v, ki, p, ca, ser := TagKindPubkeyVars()
if ki == nil || p == nil || k == nil || v == nil || ca == nil || ser == nil {
t.Fatalf("TagKindPubkeyVars should return non-nil values")
}
// Set values
ki.Set(1234)
err := p.FromPubkey(
[]byte{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
},
)
if chk.E(err) {
t.Fatalf("FromPubkey failed: %v", err)
}
k.Set('e')
v.FromIdent([]byte("test-value"))
if chk.E(err) {
t.Fatalf("FromIdent failed: %v", err)
}
ca.Set(98765)
ser.Set(12345)
// Test TagKindPubkeyEnc
enc := TagKindPubkeyEnc(k, v, ki, p, ca, ser)
if len(enc.Encs) != 7 {
t.Errorf(
"TagKindPubkeyEnc should create T with 7 encoders, got %d",
len(enc.Encs),
)
}
// Test TagKindPubkeyDec
dec := TagKindPubkeyDec(k, v, ki, p, ca, ser)
if len(dec.Encs) != 7 {
t.Errorf(
"TagKindPubkeyDec should create T with 7 encoders, got %d",
len(dec.Encs),
)
}
// Test marshaling and unmarshaling
buf := new(bytes.Buffer)
err = enc.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Create new variables for decoding
newK, newV, newKi, newP, newCa, newSer := TagKindPubkeyVars()
newDec := TagKindPubkeyDec(newK, newV, newKi, newP, newCa, newSer)
err = newDec.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the decoded values
if newKi.Get() != ki.Get() {
t.Errorf("Decoded kind %d, expected %d", newKi.Get(), ki.Get())
}
if !utils.FastEqual(newP.Bytes(), p.Bytes()) {
t.Errorf("Decoded pubkey hash %v, expected %v", newP.Bytes(), p.Bytes())
}
if newK.Letter() != k.Letter() {
t.Errorf(
"Decoded key letter %c, expected %c", newK.Letter(), k.Letter(),
)
}
if !utils.FastEqual(newV.Bytes(), v.Bytes()) {
t.Errorf("Decoded value hash %v, expected %v", newV.Bytes(), v.Bytes())
}
if newCa.Get() != ca.Get() {
t.Errorf("Decoded created at %d, expected %d", newCa.Get(), ca.Get())
}
if newSer.Get() != ser.Get() {
t.Errorf("Decoded serial %d, expected %d", newSer.Get(), ser.Get())
}
}

View File

@@ -0,0 +1,419 @@
package types
import (
"bytes"
"encoding/binary"
"testing"
)
// TestTypesSortLexicographically tests if the numeric types sort lexicographically
// when using bytes.Compare after marshaling.
func TestTypesSortLexicographically(t *testing.T) {
// Test Uint16
t.Run("Uint16", func(t *testing.T) {
testUint16Sorting(t)
})
// Test Uint24
t.Run("Uint24", func(t *testing.T) {
testUint24Sorting(t)
})
// Test Uint32
t.Run("Uint32", func(t *testing.T) {
testUint32Sorting(t)
})
// Test Uint40
t.Run("Uint40", func(t *testing.T) {
testUint40Sorting(t)
})
// Test Uint64
t.Run("Uint64", func(t *testing.T) {
testUint64Sorting(t)
})
}
// TestEdgeCases tests sorting with edge cases like zero, max values, and adjacent values
func TestEdgeCases(t *testing.T) {
// Test Uint16 edge cases
t.Run("Uint16EdgeCases", func(t *testing.T) {
testUint16EdgeCases(t)
})
// Test Uint24 edge cases
t.Run("Uint24EdgeCases", func(t *testing.T) {
testUint24EdgeCases(t)
})
// Test Uint32 edge cases
t.Run("Uint32EdgeCases", func(t *testing.T) {
testUint32EdgeCases(t)
})
// Test Uint40 edge cases
t.Run("Uint40EdgeCases", func(t *testing.T) {
testUint40EdgeCases(t)
})
// Test Uint64 edge cases
t.Run("Uint64EdgeCases", func(t *testing.T) {
testUint64EdgeCases(t)
})
}
func testUint16Sorting(t *testing.T) {
values := []uint16{1, 10, 100, 1000, 10000, 65535}
// Marshal each value
marshaledValues := make([][]byte, len(values))
for i, val := range values {
u := new(Uint16)
u.Set(val)
buf := new(bytes.Buffer)
err := u.MarshalWrite(buf)
if err != nil {
t.Fatalf("Failed to marshal Uint16 %d: %v", val, err)
}
marshaledValues[i] = buf.Bytes()
}
// Check if they sort correctly with bytes.Compare
for i := 0; i < len(marshaledValues)-1; i++ {
if bytes.Compare(marshaledValues[i], marshaledValues[i+1]) >= 0 {
t.Errorf("Uint16 values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", marshaledValues[i], marshaledValues[i+1])
}
}
}
func testUint24Sorting(t *testing.T) {
values := []uint32{1, 10, 100, 1000, 10000, 100000, 1000000, 16777215}
// Marshal each value
marshaledValues := make([][]byte, len(values))
for i, val := range values {
u := new(Uint24)
err := u.Set(val)
if err != nil {
t.Fatalf("Failed to set Uint24 %d: %v", val, err)
}
buf := new(bytes.Buffer)
err = u.MarshalWrite(buf)
if err != nil {
t.Fatalf("Failed to marshal Uint24 %d: %v", val, err)
}
marshaledValues[i] = buf.Bytes()
}
// Check if they sort correctly with bytes.Compare
for i := 0; i < len(marshaledValues)-1; i++ {
if bytes.Compare(marshaledValues[i], marshaledValues[i+1]) >= 0 {
t.Errorf("Uint24 values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", marshaledValues[i], marshaledValues[i+1])
}
}
}
func testUint32Sorting(t *testing.T) {
values := []uint32{1, 10, 100, 1000, 10000, 100000, 1000000, 4294967295}
// Marshal each value
marshaledValues := make([][]byte, len(values))
for i, val := range values {
u := new(Uint32)
u.Set(val)
buf := new(bytes.Buffer)
err := u.MarshalWrite(buf)
if err != nil {
t.Fatalf("Failed to marshal Uint32 %d: %v", val, err)
}
marshaledValues[i] = buf.Bytes()
}
// Check if they sort correctly with bytes.Compare
for i := 0; i < len(marshaledValues)-1; i++ {
if bytes.Compare(marshaledValues[i], marshaledValues[i+1]) >= 0 {
t.Errorf("Uint32 values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", marshaledValues[i], marshaledValues[i+1])
}
}
}
func testUint40Sorting(t *testing.T) {
values := []uint64{1, 10, 100, 1000, 10000, 100000, 1000000, 1099511627775}
// Marshal each value
marshaledValues := make([][]byte, len(values))
for i, val := range values {
u := new(Uint40)
err := u.Set(val)
if err != nil {
t.Fatalf("Failed to set Uint40 %d: %v", val, err)
}
buf := new(bytes.Buffer)
err = u.MarshalWrite(buf)
if err != nil {
t.Fatalf("Failed to marshal Uint40 %d: %v", val, err)
}
marshaledValues[i] = buf.Bytes()
}
// Check if they sort correctly with bytes.Compare
for i := 0; i < len(marshaledValues)-1; i++ {
if bytes.Compare(marshaledValues[i], marshaledValues[i+1]) >= 0 {
t.Errorf("Uint40 values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", marshaledValues[i], marshaledValues[i+1])
}
}
}
func testUint64Sorting(t *testing.T) {
values := []uint64{1, 10, 100, 1000, 10000, 100000, 1000000, 18446744073709551615}
// Marshal each value
marshaledValues := make([][]byte, len(values))
for i, val := range values {
u := new(Uint64)
u.Set(val)
buf := new(bytes.Buffer)
err := u.MarshalWrite(buf)
if err != nil {
t.Fatalf("Failed to marshal Uint64 %d: %v", val, err)
}
marshaledValues[i] = buf.Bytes()
}
// Check if they sort correctly with bytes.Compare
for i := 0; i < len(marshaledValues)-1; i++ {
if bytes.Compare(marshaledValues[i], marshaledValues[i+1]) >= 0 {
t.Errorf("Uint64 values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", marshaledValues[i], marshaledValues[i+1])
}
}
}
// Edge case test functions
func testUint16EdgeCases(t *testing.T) {
// Test edge cases: 0, max value, and adjacent values
values := []uint16{0, 1, 2, 65534, 65535}
// Marshal each value
marshaledValues := make([][]byte, len(values))
for i, val := range values {
u := new(Uint16)
u.Set(val)
buf := new(bytes.Buffer)
err := u.MarshalWrite(buf)
if err != nil {
t.Fatalf("Failed to marshal Uint16 %d: %v", val, err)
}
marshaledValues[i] = buf.Bytes()
}
// Check if they sort correctly with bytes.Compare
for i := 0; i < len(marshaledValues)-1; i++ {
if bytes.Compare(marshaledValues[i], marshaledValues[i+1]) >= 0 {
t.Errorf("Uint16 edge case values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", marshaledValues[i], marshaledValues[i+1])
}
}
}
func testUint24EdgeCases(t *testing.T) {
// Test edge cases: 0, max value, and adjacent values
values := []uint32{0, 1, 2, 16777214, 16777215}
// Marshal each value
marshaledValues := make([][]byte, len(values))
for i, val := range values {
u := new(Uint24)
err := u.Set(val)
if err != nil {
t.Fatalf("Failed to set Uint24 %d: %v", val, err)
}
buf := new(bytes.Buffer)
err = u.MarshalWrite(buf)
if err != nil {
t.Fatalf("Failed to marshal Uint24 %d: %v", val, err)
}
marshaledValues[i] = buf.Bytes()
}
// Check if they sort correctly with bytes.Compare
for i := 0; i < len(marshaledValues)-1; i++ {
if bytes.Compare(marshaledValues[i], marshaledValues[i+1]) >= 0 {
t.Errorf("Uint24 edge case values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", marshaledValues[i], marshaledValues[i+1])
}
}
}
func testUint32EdgeCases(t *testing.T) {
// Test edge cases: 0, max value, and adjacent values
values := []uint32{0, 1, 2, 4294967294, 4294967295}
// Marshal each value
marshaledValues := make([][]byte, len(values))
for i, val := range values {
u := new(Uint32)
u.Set(val)
buf := new(bytes.Buffer)
err := u.MarshalWrite(buf)
if err != nil {
t.Fatalf("Failed to marshal Uint32 %d: %v", val, err)
}
marshaledValues[i] = buf.Bytes()
}
// Check if they sort correctly with bytes.Compare
for i := 0; i < len(marshaledValues)-1; i++ {
if bytes.Compare(marshaledValues[i], marshaledValues[i+1]) >= 0 {
t.Errorf("Uint32 edge case values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", marshaledValues[i], marshaledValues[i+1])
}
}
}
func testUint40EdgeCases(t *testing.T) {
// Test edge cases: 0, max value, and adjacent values
values := []uint64{0, 1, 2, 1099511627774, 1099511627775}
// Marshal each value
marshaledValues := make([][]byte, len(values))
for i, val := range values {
u := new(Uint40)
err := u.Set(val)
if err != nil {
t.Fatalf("Failed to set Uint40 %d: %v", val, err)
}
buf := new(bytes.Buffer)
err = u.MarshalWrite(buf)
if err != nil {
t.Fatalf("Failed to marshal Uint40 %d: %v", val, err)
}
marshaledValues[i] = buf.Bytes()
}
// Check if they sort correctly with bytes.Compare
for i := 0; i < len(marshaledValues)-1; i++ {
if bytes.Compare(marshaledValues[i], marshaledValues[i+1]) >= 0 {
t.Errorf("Uint40 edge case values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", marshaledValues[i], marshaledValues[i+1])
}
}
}
func testUint64EdgeCases(t *testing.T) {
// Test edge cases: 0, max value, and adjacent values
values := []uint64{0, 1, 2, 18446744073709551614, 18446744073709551615}
// Marshal each value
marshaledValues := make([][]byte, len(values))
for i, val := range values {
u := new(Uint64)
u.Set(val)
buf := new(bytes.Buffer)
err := u.MarshalWrite(buf)
if err != nil {
t.Fatalf("Failed to marshal Uint64 %d: %v", val, err)
}
marshaledValues[i] = buf.Bytes()
}
// Check if they sort correctly with bytes.Compare
for i := 0; i < len(marshaledValues)-1; i++ {
if bytes.Compare(marshaledValues[i], marshaledValues[i+1]) >= 0 {
t.Errorf("Uint64 edge case values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", marshaledValues[i], marshaledValues[i+1])
}
}
}
// TestEndianness demonstrates why BigEndian is used instead of LittleEndian
// for lexicographical sorting with bytes.Compare
func TestEndianness(t *testing.T) {
// Test with uint32 values
values := []uint32{1, 10, 100, 1000, 10000}
// Marshal each value using BigEndian
bigEndianValues := make([][]byte, len(values))
for i, val := range values {
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, val)
bigEndianValues[i] = buf
}
// Marshal each value using LittleEndian
littleEndianValues := make([][]byte, len(values))
for i, val := range values {
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, val)
littleEndianValues[i] = buf
}
// Check if BigEndian values sort correctly with bytes.Compare
t.Log("Testing BigEndian sorting:")
for i := 0; i < len(bigEndianValues)-1; i++ {
result := bytes.Compare(bigEndianValues[i], bigEndianValues[i+1])
t.Logf("Compare %d with %d: result = %d", values[i], values[i+1], result)
if result >= 0 {
t.Errorf("BigEndian values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", bigEndianValues[i], bigEndianValues[i+1])
}
}
// Check if LittleEndian values sort correctly with bytes.Compare
t.Log("Testing LittleEndian sorting:")
correctOrder := true
for i := 0; i < len(littleEndianValues)-1; i++ {
result := bytes.Compare(littleEndianValues[i], littleEndianValues[i+1])
t.Logf("Compare %d with %d: result = %d", values[i], values[i+1], result)
if result >= 0 {
correctOrder = false
t.Logf("LittleEndian values don't sort correctly: %v should be less than %v",
values[i], values[i+1])
t.Logf("Bytes representation: %v vs %v", littleEndianValues[i], littleEndianValues[i+1])
}
}
// We expect LittleEndian to NOT sort correctly
if correctOrder {
t.Error("LittleEndian values unexpectedly sorted correctly")
} else {
t.Log("As expected, LittleEndian values don't sort correctly with bytes.Compare")
}
}

View File

@@ -0,0 +1,38 @@
package types
import (
"io"
"crypto.orly/sha256"
"lol.mleku.dev/errorf"
)
const IdLen = sha256.Size
type Id struct {
val [IdLen]byte
}
func (fi *Id) FromId(id []byte) (err error) {
if len(id) != IdLen {
err = errorf.E(
"fullid.FromId: invalid ID length, got %d require %d", len(id),
IdLen,
)
return
}
copy(fi.val[:], id)
return
}
func (fi *Id) Bytes() (b []byte) { return fi.val[:] }
func (fi *Id) MarshalWrite(w io.Writer) (err error) {
_, err = w.Write(fi.val[:])
return
}
func (fi *Id) UnmarshalRead(r io.Reader) (err error) {
copy(fi.val[:], fi.val[:IdLen])
_, err = r.Read(fi.val[:])
return
}

View File

@@ -0,0 +1,115 @@
package types
import (
"bytes"
"testing"
"lol.mleku.dev/chk"
"utils.orly"
"crypto.orly/sha256"
)
func TestFromId(t *testing.T) {
// Create a valid ID (32 bytes)
validId := make([]byte, sha256.Size)
for i := 0; i < sha256.Size; i++ {
validId[i] = byte(i)
}
// Create an invalid ID (wrong size)
invalidId := make([]byte, sha256.Size-1)
// Test with valid ID
fi := &Id{}
err := fi.FromId(validId)
if chk.E(err) {
t.Fatalf("FromId failed with valid ID: %v", err)
}
// Verify the ID was set correctly
if !utils.FastEqual(fi.Bytes(), validId) {
t.Errorf(
"FromId did not set the ID correctly: got %v, want %v", fi.Bytes(),
validId,
)
}
// Test with invalid ID
fi = &Id{}
err = fi.FromId(invalidId)
if err == nil {
t.Errorf("FromId should have failed with invalid ID size")
}
}
func TestIdMarshalWriteUnmarshalRead(t *testing.T) {
// Create a ID with a known value
fi1 := &Id{}
validId := make([]byte, sha256.Size)
for i := 0; i < sha256.Size; i++ {
validId[i] = byte(i)
}
err := fi1.FromId(validId)
if chk.E(err) {
t.Fatalf("FromId failed: %v", err)
}
// Test MarshalWrite
buf := new(bytes.Buffer)
err = fi1.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Verify the written bytes
if !utils.FastEqual(buf.Bytes(), validId) {
t.Errorf("MarshalWrite wrote %v, want %v", buf.Bytes(), validId)
}
// Test UnmarshalRead
fi2 := &Id{}
err = fi2.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the read value
if !utils.FastEqual(fi2.Bytes(), validId) {
t.Errorf("UnmarshalRead read %v, want %v", fi2.Bytes(), validId)
}
}
func TestIdUnmarshalReadWithCorruptedData(t *testing.T) {
// Create a ID with a known value
fi1 := &Id{}
validId := make([]byte, sha256.Size)
for i := 0; i < sha256.Size; i++ {
validId[i] = byte(i)
}
err := fi1.FromId(validId)
if chk.E(err) {
t.Fatalf("FromId failed: %v", err)
}
// Create a second ID with a different value
fi2 := &Id{}
differentId := make([]byte, sha256.Size)
for i := 0; i < sha256.Size; i++ {
differentId[i] = byte(sha256.Size - i - 1)
}
err = fi2.FromId(differentId)
if chk.E(err) {
t.Fatalf("FromId failed: %v", err)
}
// Test UnmarshalRead with corrupted data (less than Len bytes)
corruptedData := make([]byte, sha256.Size/2)
fi2.UnmarshalRead(bytes.NewBuffer(corruptedData))
// The UnmarshalRead method should not have copied the original data to itself
// before reading, so the value should be partially overwritten
if utils.FastEqual(fi2.Bytes(), differentId) {
t.Errorf("UnmarshalRead did not modify the value as expected")
}
}

View File

@@ -0,0 +1,31 @@
package types
import (
"io"
"crypto.orly/sha256"
)
const IdentLen = 8
type Ident struct{ val [IdentLen]byte }
func (i *Ident) FromIdent(id []byte) {
idh := sha256.Sum256(id)
copy(i.val[:], idh[:IdentLen])
return
}
func (i *Ident) Bytes() (b []byte) { return i.val[:] }
func (i *Ident) MarshalWrite(w io.Writer) (err error) {
_, err = w.Write(i.val[:])
return
}
func (i *Ident) UnmarshalRead(r io.Reader) (err error) {
copy(i.val[:], i.val[:IdentLen])
_, err = r.Read(i.val[:])
return
}

View File

@@ -0,0 +1,99 @@
package types
import (
"bytes"
"testing"
"crypto.orly/sha256"
"lol.mleku.dev/chk"
"utils.orly"
)
func TestFromIdent(t *testing.T) {
var err error
// Create a test identity
testIdent := []byte("test-identity")
// Calculate the expected hash
idh := sha256.Sum256(testIdent)
expected := idh[:IdentLen]
// Test FromIdent
i := &Ident{}
i.FromIdent(testIdent)
if chk.E(err) {
t.Fatalf("FromIdent failed: %v", err)
}
// Verify the hash was set correctly
if !utils.FastEqual(i.Bytes(), expected) {
t.Errorf(
"FromIdent did not set the hash correctly: got %v, want %v",
i.Bytes(), expected,
)
}
}
func TestIdent_MarshalWriteUnmarshalRead(t *testing.T) {
var err error
// Create a Ident with a known value
i1 := &Ident{}
testIdent := []byte("test-identity")
i1.FromIdent(testIdent)
if chk.E(err) {
t.Fatalf("FromIdent failed: %v", err)
}
// Test MarshalWrite
buf := new(bytes.Buffer)
err = i1.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Verify the written bytes
if !utils.FastEqual(buf.Bytes(), i1.Bytes()) {
t.Errorf("MarshalWrite wrote %v, want %v", buf.Bytes(), i1.Bytes())
}
// Test UnmarshalRead
i2 := &Ident{}
err = i2.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the read value
if !utils.FastEqual(i2.Bytes(), i1.Bytes()) {
t.Errorf("UnmarshalRead read %v, want %v", i2.Bytes(), i1.Bytes())
}
}
func TestIdent_UnmarshalReadWithCorruptedData(t *testing.T) {
var err error
// Create a Ident with a known value
i1 := &Ident{}
testIdent1 := []byte("test-identity-1")
i1.FromIdent(testIdent1)
if chk.E(err) {
t.Fatalf("FromIdent failed: %v", err)
}
// Create a second Ident with a different value
i2 := &Ident{}
testIdent2 := []byte("test-identity-2")
i2.FromIdent(testIdent2)
if chk.E(err) {
t.Fatalf("FromIdent failed: %v", err)
}
// Test UnmarshalRead with corrupted data (less than IdentLen bytes)
corruptedData := make([]byte, IdentLen/2)
i2.UnmarshalRead(bytes.NewBuffer(corruptedData))
// The UnmarshalRead method should not have copied the original data to itself
// before reading, so the value should be partially overwritten
if utils.FastEqual(i2.Bytes(), i1.Bytes()) {
t.Errorf("UnmarshalRead did not modify the value as expected")
}
}

View File

@@ -0,0 +1,87 @@
package types
import (
"encoding/base64"
"io"
"crypto.orly/sha256"
"encoders.orly/hex"
"lol.mleku.dev/chk"
"lol.mleku.dev/errorf"
)
const IdHashLen = 8
type IdHash struct{ val [IdHashLen]byte }
func (i *IdHash) Set(idh []byte) {
if len(idh) != IdHashLen {
panic("invalid IdHash length")
}
copy(i.val[:], idh)
}
func (i *IdHash) FromId(id []byte) (err error) {
if len(id) != sha256.Size {
err = errorf.E(
"FromId: invalid ID length, got %d require %d", len(id),
sha256.Size,
)
return
}
idh := sha256.Sum256(id)
copy(i.val[:], idh[:IdHashLen])
return
}
func (i *IdHash) FromIdBase64(idb64 string) (err error) {
// Decode the base64 string
decoded, err := base64.RawURLEncoding.DecodeString(idb64)
if chk.E(err) {
return
}
// Check if the decoded ID has the correct length
if len(decoded) != sha256.Size {
err = errorf.E(
"FromIdBase64: invalid ID length, got %d require %d", len(decoded),
sha256.Size,
)
return
}
// Hash the decoded ID and take the first IdHashLen bytes
idh := sha256.Sum256(decoded)
copy(i.val[:], idh[:IdHashLen])
return
}
func (i *IdHash) FromIdHex(idh string) (err error) {
var id []byte
if id, err = hex.Dec(idh); chk.E(err) {
return
}
if len(id) != sha256.Size {
err = errorf.E(
"FromIdHex: invalid ID length, got %d require %d", len(id),
sha256.Size,
)
return
}
h := sha256.Sum256(id)
copy(i.val[:], h[:IdHashLen])
return
}
func (i *IdHash) Bytes() (b []byte) { return i.val[:] }
func (i *IdHash) MarshalWrite(w io.Writer) (err error) {
_, err = w.Write(i.val[:])
return
}
func (i *IdHash) UnmarshalRead(r io.Reader) (err error) {
_, err = r.Read(i.val[:])
return
}

View File

@@ -0,0 +1,186 @@
package types
import (
"bytes"
"encoding/base64"
"testing"
"crypto.orly/sha256"
"encoders.orly/hex"
"lol.mleku.dev/chk"
"utils.orly"
)
func TestFromIdHash(t *testing.T) {
// Create a valid ID (32 bytes)
validId := make([]byte, sha256.Size)
for i := 0; i < sha256.Size; i++ {
validId[i] = byte(i)
}
// Create an invalid ID (wrong size)
invalidId := make([]byte, sha256.Size-1)
// Test with valid ID
i := new(IdHash)
err := i.FromId(validId)
if chk.E(err) {
t.Fatalf("FromId failed with valid ID: %v", err)
}
// Calculate the expected hash
idh := sha256.Sum256(validId)
expected := idh[:IdHashLen]
// Verify the hash was set correctly
if !utils.FastEqual(i.Bytes(), expected) {
t.Errorf(
"FromId did not set the hash correctly: got %v, want %v", i.Bytes(),
expected,
)
}
// Test with invalid ID
i = new(IdHash)
err = i.FromId(invalidId)
if err == nil {
t.Errorf("FromId should have failed with invalid ID size")
}
}
func TestFromIdBase64(t *testing.T) {
// Create a valid ID (32 bytes)
validId := make([]byte, sha256.Size)
for i := 0; i < sha256.Size; i++ {
validId[i] = byte(i)
}
// Encode the ID as base64
validIdBase64 := base64.RawURLEncoding.EncodeToString(validId)
// Test with valid base64 ID
i := new(IdHash)
err := i.FromIdBase64(validIdBase64)
if chk.E(err) {
t.Fatalf("FromIdBase64 failed with valid ID: %v", err)
}
// Calculate the expected hash
idh := sha256.Sum256(validId)
expected := idh[:IdHashLen]
// Verify the hash was set correctly
if !utils.FastEqual(i.Bytes(), expected) {
t.Errorf(
"FromIdBase64 did not set the hash correctly: got %v, want %v",
i.Bytes(), expected,
)
}
// Test with invalid base64 ID
i = new(IdHash)
err = i.FromIdBase64("invalid-base64")
if err == nil {
t.Errorf("FromIdBase64 should have failed with invalid base64")
}
}
func TestFromIdHex(t *testing.T) {
// Create a valid ID (32 bytes)
validId := make([]byte, sha256.Size)
for i := 0; i < sha256.Size; i++ {
validId[i] = byte(i)
}
// Encode the ID as hex
validIdHex := hex.Enc(validId)
// Test with valid hex ID
i := new(IdHash)
err := i.FromIdHex(validIdHex)
if chk.E(err) {
t.Fatalf("FromIdHex failed with valid ID: %v", err)
}
// Calculate the expected hash
idh := sha256.Sum256(validId)
expected := idh[:IdHashLen]
// Verify the hash was set correctly
if !utils.FastEqual(i.Bytes(), expected) {
t.Errorf(
"FromIdHex did not set the hash correctly: got %v, want %v",
i.Bytes(), expected,
)
}
// Test with invalid hex ID (wrong size)
i = new(IdHash)
err = i.FromIdHex(validIdHex[:len(validIdHex)-2])
if err == nil {
t.Errorf("FromIdHex should have failed with invalid ID size")
}
// Test with invalid hex ID (not hex)
i = new(IdHash)
err = i.FromIdHex("invalid-hex")
if err == nil {
t.Errorf("FromIdHex should have failed with invalid hex")
}
}
func TestIdHashMarshalWriteUnmarshalRead(t *testing.T) {
// Create a IdHash with a known value
i1 := new(IdHash)
validId := make([]byte, sha256.Size)
for i := 0; i < sha256.Size; i++ {
validId[i] = byte(i)
}
err := i1.FromId(validId)
if chk.E(err) {
t.Fatalf("FromId failed: %v", err)
}
// Test MarshalWrite
buf := new(bytes.Buffer)
err = i1.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Verify the written bytes
if !utils.FastEqual(buf.Bytes(), i1.Bytes()) {
t.Errorf("MarshalWrite wrote %v, want %v", buf.Bytes(), i1.Bytes())
}
// Test UnmarshalRead
i2 := new(IdHash)
err = i2.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the read value
if !utils.FastEqual(i2.Bytes(), i1.Bytes()) {
t.Errorf("UnmarshalRead read %v, want %v", i2.Bytes(), i1.Bytes())
}
}
func TestUnmarshalReadWithEmptyVal(t *testing.T) {
// Create a IdHash with an empty val
i := new(IdHash)
// Create some test data
testData := []byte{1, 2, 3, 4, 5, 6, 7, 8}
// Test UnmarshalRead
err := i.UnmarshalRead(bytes.NewBuffer(testData))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the read value
if !utils.FastEqual(i.Bytes(), testData) {
t.Errorf("UnmarshalRead read %v, want %v", i.Bytes(), testData)
}
}

View File

@@ -0,0 +1,31 @@
package types
import (
"io"
"lol.mleku.dev/chk"
)
const LetterLen = 1
type Letter struct {
val byte
}
func (p *Letter) Set(lb byte) { p.val = lb }
func (p *Letter) Letter() byte { return p.val }
func (p *Letter) MarshalWrite(w io.Writer) (err error) {
_, err = w.Write([]byte{p.val})
return
}
func (p *Letter) UnmarshalRead(r io.Reader) (err error) {
val := make([]byte, 1)
if _, err = r.Read(val); chk.E(err) {
return
}
p.val = val[0]
return
}

View File

@@ -0,0 +1,127 @@
package types
import (
"bytes"
"testing"
"lol.mleku.dev/chk"
)
func TestLetter_New(t *testing.T) {
// Test with a valid letter
l := new(Letter)
l.Set('A')
if l == nil {
t.Fatal("New() returned nil")
}
if l.Letter() != 'A' {
t.Errorf(
"New('A') created a Letter with letter %c, want %c", l.Letter(),
'A',
)
}
}
func TestLetter_Set(t *testing.T) {
// Create a Letter with a known value
l := new(Letter)
l.Set('A')
// Test Set
l.Set('B')
if l.Letter() != 'B' {
t.Errorf(
"Set('B') did not set the letter correctly: got %c, want %c",
l.Letter(), 'B',
)
}
}
func TestLetter(t *testing.T) {
// Create a Letter with a known value
l := new(Letter)
l.Set('A')
// Test Letter
if l.Letter() != 'A' {
t.Errorf("Letter() returned %c, want %c", l.Letter(), 'A')
}
}
func TestLetter_MarshalWriteUnmarshalRead(t *testing.T) {
// Create a Letter with a known value
l1 := new(Letter)
l1.Set('A')
// Test MarshalWrite
buf := new(bytes.Buffer)
err := l1.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Verify the written bytes
if buf.Len() != 1 || buf.Bytes()[0] != 'A' {
t.Errorf("MarshalWrite wrote %v, want [%d]", buf.Bytes(), 'A')
}
// Test UnmarshalRead
l2 := new(Letter)
l2.Set('B') // Start with a different value
err = l2.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the read value
if l2.Letter() != 'A' {
t.Errorf("UnmarshalRead read %c, want %c", l2.Letter(), 'A')
}
}
func TestLetter_UnmarshalReadWithEmptyReader(t *testing.T) {
// Create a Letter with a known value
l := new(Letter)
l.Set('A')
// Test UnmarshalRead with an empty reader
err := l.UnmarshalRead(bytes.NewBuffer([]byte{}))
if err == nil {
t.Errorf("UnmarshalRead should have failed with an empty reader")
}
}
func TestLetter_EdgeCases(t *testing.T) {
// Test with minimum value (0)
l1 := new(Letter)
if l1.Letter() != 0 {
t.Errorf(
"New(0) created a Letter with letter %d, want %d", l1.Letter(), 0,
)
}
// Test with maximum value (255)
l2 := new(Letter)
l2.Set(255)
if l2.Letter() != 255 {
t.Errorf(
"New(255) created a Letter with letter %d, want %d", l2.Letter(),
255,
)
}
// Test with special characters
specialChars := []byte{
'\n', '\t', '\r', ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')',
'*', '+', ',', '-', '.', '/',
}
for _, c := range specialChars {
l := new(Letter)
l.Set(c)
if l.Letter() != c {
t.Errorf(
"New(%d) created a Letter with letter %d, want %d", c,
l.Letter(), c,
)
}
}
}

View File

@@ -0,0 +1,58 @@
package types
import (
"io"
"crypto.orly/ec/schnorr"
"crypto.orly/sha256"
"encoders.orly/hex"
"lol.mleku.dev/chk"
"lol.mleku.dev/errorf"
)
const PubHashLen = 8
type PubHash struct{ val [PubHashLen]byte }
func (ph *PubHash) FromPubkey(pk []byte) (err error) {
if len(pk) != schnorr.PubKeyBytesLen {
err = errorf.E(
"invalid Pubkey length, got %d require %d",
len(pk), schnorr.PubKeyBytesLen,
)
return
}
pkh := sha256.Sum256(pk)
copy(ph.val[:], pkh[:PubHashLen])
return
}
func (ph *PubHash) FromPubkeyHex(pk string) (err error) {
if len(pk) != schnorr.PubKeyBytesLen*2 {
err = errorf.E(
"invalid Pubkey length, got %d require %d",
len(pk), schnorr.PubKeyBytesLen*2,
)
return
}
var pkb []byte
if pkb, err = hex.Dec(pk); chk.E(err) {
return
}
h := sha256.Sum256(pkb)
copy(ph.val[:], h[:PubHashLen])
return
}
func (ph *PubHash) Bytes() (b []byte) { return ph.val[:] }
func (ph *PubHash) MarshalWrite(w io.Writer) (err error) {
_, err = w.Write(ph.val[:])
return
}
func (ph *PubHash) UnmarshalRead(r io.Reader) (err error) {
copy(ph.val[:], ph.val[:PubHashLen])
_, err = r.Read(ph.val[:])
return
}

View File

@@ -0,0 +1,164 @@
package types
import (
"bytes"
"testing"
"crypto.orly/ec/schnorr"
"crypto.orly/sha256"
"encoders.orly/hex"
"lol.mleku.dev/chk"
"utils.orly"
)
func TestPubHash_FromPubkey(t *testing.T) {
// Create a valid pubkey (32 bytes)
validPubkey := make([]byte, schnorr.PubKeyBytesLen)
for i := 0; i < schnorr.PubKeyBytesLen; i++ {
validPubkey[i] = byte(i)
}
// Create an invalid pubkey (wrong size)
invalidPubkey := make([]byte, schnorr.PubKeyBytesLen-1)
// Test with valid pubkey
ph := &PubHash{}
err := ph.FromPubkey(validPubkey)
if chk.E(err) {
t.Fatalf("FromPubkey failed with valid pubkey: %v", err)
}
// Calculate the expected hash
pkh := sha256.Sum256(validPubkey)
expected := pkh[:PubHashLen]
// Verify the hash was set correctly
if !utils.FastEqual(ph.Bytes(), expected) {
t.Errorf(
"FromPubkey did not set the hash correctly: got %v, want %v",
ph.Bytes(), expected,
)
}
// Test with invalid pubkey
ph = &PubHash{}
err = ph.FromPubkey(invalidPubkey)
if err == nil {
t.Errorf("FromPubkey should have failed with invalid pubkey size")
}
}
func TestPubHash_FromPubkeyHex(t *testing.T) {
// Create a valid pubkey (32 bytes)
validPubkey := make([]byte, schnorr.PubKeyBytesLen)
for i := 0; i < schnorr.PubKeyBytesLen; i++ {
validPubkey[i] = byte(i)
}
// Encode the pubkey as hex
validPubkeyHex := hex.Enc(validPubkey)
// Test with valid hex pubkey
ph := &PubHash{}
err := ph.FromPubkeyHex(validPubkeyHex)
if chk.E(err) {
t.Fatalf("FromPubkeyHex failed with valid pubkey: %v", err)
}
// Calculate the expected hash
pkh := sha256.Sum256(validPubkey)
expected := pkh[:PubHashLen]
// Verify the hash was set correctly
if !utils.FastEqual(ph.Bytes(), expected) {
t.Errorf(
"FromPubkeyHex did not set the hash correctly: got %v, want %v",
ph.Bytes(), expected,
)
}
// Test with invalid hex pubkey (wrong size)
ph = &PubHash{}
err = ph.FromPubkeyHex(validPubkeyHex[:len(validPubkeyHex)-2])
if err == nil {
t.Errorf("FromPubkeyHex should have failed with invalid pubkey size")
}
// Test with invalid hex pubkey (not hex)
ph = &PubHash{}
err = ph.FromPubkeyHex("invalid-hex")
if err == nil {
t.Errorf("FromPubkeyHex should have failed with invalid hex")
}
}
func TestPubHash_MarshalWriteUnmarshalRead(t *testing.T) {
// Create a PubHash with a known value
ph1 := &PubHash{}
validPubkey := make([]byte, schnorr.PubKeyBytesLen)
for i := 0; i < schnorr.PubKeyBytesLen; i++ {
validPubkey[i] = byte(i)
}
err := ph1.FromPubkey(validPubkey)
if chk.E(err) {
t.Fatalf("FromPubkey failed: %v", err)
}
// Test MarshalWrite
buf := new(bytes.Buffer)
err = ph1.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Verify the written bytes
if !utils.FastEqual(buf.Bytes(), ph1.Bytes()) {
t.Errorf("MarshalWrite wrote %v, want %v", buf.Bytes(), ph1.Bytes())
}
// Test UnmarshalRead
ph2 := &PubHash{}
err = ph2.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the read value
if !utils.FastEqual(ph2.Bytes(), ph1.Bytes()) {
t.Errorf("UnmarshalRead read %v, want %v", ph2.Bytes(), ph1.Bytes())
}
}
func TestPubHash_UnmarshalReadWithCorruptedData(t *testing.T) {
// Create a PubHash with a known value
ph1 := &PubHash{}
validPubkey1 := make([]byte, schnorr.PubKeyBytesLen)
for i := 0; i < schnorr.PubKeyBytesLen; i++ {
validPubkey1[i] = byte(i)
}
err := ph1.FromPubkey(validPubkey1)
if chk.E(err) {
t.Fatalf("FromPubkey failed: %v", err)
}
// Create a second PubHash with a different value
ph2 := &PubHash{}
validPubkey2 := make([]byte, schnorr.PubKeyBytesLen)
for i := 0; i < schnorr.PubKeyBytesLen; i++ {
validPubkey2[i] = byte(schnorr.PubKeyBytesLen - i - 1)
}
err = ph2.FromPubkey(validPubkey2)
if chk.E(err) {
t.Fatalf("FromPubkey failed: %v", err)
}
// Test UnmarshalRead with corrupted data (less than PubHashLen bytes)
corruptedData := make([]byte, PubHashLen/2)
ph2.UnmarshalRead(bytes.NewBuffer(corruptedData))
// The UnmarshalRead method should not have copied the original data to itself
// before reading, so the value should be partially overwritten
if utils.FastEqual(ph2.Bytes(), ph1.Bytes()) {
t.Errorf("UnmarshalRead did not modify the value as expected")
}
}

View File

@@ -0,0 +1,56 @@
package types
import (
"bytes"
"io"
"lol.mleku.dev/chk"
)
const TimestampLen = 8
type Timestamp struct{ val int64 }
func (ts *Timestamp) FromInt(t int) { ts.val = int64(t) }
func (ts *Timestamp) FromInt64(t int64) { ts.val = t }
func FromBytes(timestampBytes []byte) (ts *Timestamp, err error) {
v := new(Uint64)
if err = v.UnmarshalRead(bytes.NewBuffer(timestampBytes)); chk.E(err) {
return
}
ts = &Timestamp{val: int64(v.Get())}
return
}
func (ts *Timestamp) ToTimestamp() (timestamp int64) {
return ts.val
}
func (ts *Timestamp) Bytes() (b []byte, err error) {
v := new(Uint64)
v.Set(uint64(ts.val))
buf := new(bytes.Buffer)
if err = v.MarshalWrite(buf); chk.E(err) {
return
}
b = buf.Bytes()
return
}
func (ts *Timestamp) MarshalWrite(w io.Writer) (err error) {
v := new(Uint64)
v.Set(uint64(ts.val))
if err = v.MarshalWrite(w); chk.E(err) {
return
}
return
}
func (ts *Timestamp) UnmarshalRead(r io.Reader) (err error) {
v := new(Uint64)
if err = v.UnmarshalRead(r); chk.E(err) {
return
}
ts.val = int64(v.Get())
return
}

View File

@@ -0,0 +1,243 @@
package types
import (
"bytes"
"testing"
"time"
"lol.mleku.dev/chk"
)
func TestTimestamp_FromInt(t *testing.T) {
// Test with a positive value
ts := &Timestamp{}
ts.FromInt(12345)
if ts.val != 12345 {
t.Errorf(
"FromInt(12345) did not set the value correctly: got %d, want %d",
ts.val, 12345,
)
}
// Test with a negative value
ts = &Timestamp{}
ts.FromInt(-12345)
if ts.val != -12345 {
t.Errorf(
"FromInt(-12345) did not set the value correctly: got %d, want %d",
ts.val, -12345,
)
}
// Test with zero
ts = &Timestamp{}
ts.FromInt(0)
if ts.val != 0 {
t.Errorf(
"FromInt(0) did not set the value correctly: got %d, want %d",
ts.val, 0,
)
}
}
func TestTimestamp_FromInt64(t *testing.T) {
// Test with a positive value
ts := &Timestamp{}
ts.FromInt64(12345)
if ts.val != 12345 {
t.Errorf(
"FromInt64(12345) did not set the value correctly: got %d, want %d",
ts.val, 12345,
)
}
// Test with a negative value
ts = &Timestamp{}
ts.FromInt64(-12345)
if ts.val != -12345 {
t.Errorf(
"FromInt64(-12345) did not set the value correctly: got %d, want %d",
ts.val, -12345,
)
}
// Test with zero
ts = &Timestamp{}
ts.FromInt64(0)
if ts.val != 0 {
t.Errorf(
"FromInt64(0) did not set the value correctly: got %d, want %d",
ts.val, 0,
)
}
// Test with a large value
ts = &Timestamp{}
largeValue := int64(1) << 60
ts.FromInt64(largeValue)
if ts.val != largeValue {
t.Errorf(
"FromInt64(%d) did not set the value correctly: got %d, want %d",
largeValue, ts.val, largeValue,
)
}
}
func TestTimestamp_FromBytes(t *testing.T) {
// Create a number.Uint64 with a known value
v := new(Uint64)
v.Set(12345)
// Marshal it to bytes
buf := new(bytes.Buffer)
err := v.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Test FromBytes
ts, err := FromBytes(buf.Bytes())
if chk.E(err) {
t.Fatalf("FromBytes failed: %v", err)
}
if ts.val != 12345 {
t.Errorf(
"FromBytes did not set the value correctly: got %d, want %d",
ts.val, 12345,
)
}
// Test with invalid bytes
_, err = FromBytes([]byte{1})
if err == nil {
t.Errorf("FromBytes should have failed with invalid bytes")
}
}
func TestTimestamp_ToTimestamp(t *testing.T) {
// Test with a positive value
ts := &Timestamp{val: 12345}
timestamp := ts.ToTimestamp()
if timestamp != 12345 {
t.Errorf("ToTimestamp() returned %d, want %d", timestamp, 12345)
}
// Test with a negative value
ts = &Timestamp{val: -12345}
timestamp = ts.ToTimestamp()
if timestamp != -12345 {
t.Errorf("ToTimestamp() returned %d, want %d", timestamp, -12345)
}
// Test with zero
ts = &Timestamp{val: 0}
timestamp = ts.ToTimestamp()
if timestamp != 0 {
t.Errorf("ToTimestamp() returned %d, want %d", timestamp, 0)
}
}
func TestTimestamp_Bytes(t *testing.T) {
// Test with a positive value
ts := &Timestamp{val: 12345}
b, err := ts.Bytes()
if chk.E(err) {
t.Fatalf("Bytes() failed: %v", err)
}
// Verify the bytes
v := new(Uint64)
err = v.UnmarshalRead(bytes.NewBuffer(b))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
if v.Get() != 12345 {
t.Errorf("Bytes() returned bytes for %d, want %d", v.Get(), 12345)
}
// Skip negative value test for Bytes() since uint64 can't represent negative values
// Instead, we'll test that MarshalWrite and UnmarshalRead work correctly with negative values
// in the TestMarshalWriteUnmarshalRead function
}
func TestTimestamp_MarshalWriteUnmarshalRead(t *testing.T) {
// Test with a positive value
ts1 := &Timestamp{val: 12345}
buf := new(bytes.Buffer)
err := ts1.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Test UnmarshalRead
ts2 := &Timestamp{}
err = ts2.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the read value
if ts2.val != 12345 {
t.Errorf("UnmarshalRead read %d, want %d", ts2.val, 12345)
}
// Test with a negative value
ts1 = &Timestamp{val: -12345}
buf = new(bytes.Buffer)
err = ts1.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Test UnmarshalRead
ts2 = &Timestamp{}
err = ts2.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Verify the read value
if ts2.val != -12345 {
t.Errorf("UnmarshalRead read %d, want %d", ts2.val, -12345)
}
}
func TestTimestamp_WithCurrentTime(t *testing.T) {
// Get the current time
now := time.Now().Unix()
// Create a timestamp with the current time
ts := &Timestamp{}
ts.FromInt64(now)
// Verify the value
if ts.val != now {
t.Errorf(
"FromInt64(%d) did not set the value correctly: got %d, want %d",
now, ts.val, now,
)
}
// Test ToTimestamp
timestamp := ts.ToTimestamp()
if timestamp != now {
t.Errorf("ToTimestamp() returned %d, want %d", timestamp, now)
}
// Test MarshalWrite and UnmarshalRead
buf := new(bytes.Buffer)
err := ts.MarshalWrite(buf)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
ts2 := &Timestamp{}
err = ts2.UnmarshalRead(bytes.NewBuffer(buf.Bytes()))
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
if ts2.val != now {
t.Errorf("UnmarshalRead read %d, want %d", ts2.val, now)
}
}

View File

@@ -0,0 +1,115 @@
package types
import (
"encoding/binary"
"io"
)
// Uint16 is a codec for encoding and decoding 16-bit unsigned integers.
type Uint16 struct {
value uint16
}
// Set sets the value as a uint16.
func (c *Uint16) Set(value uint16) {
c.value = value
}
// Get gets the value as a uint16.
func (c *Uint16) Get() uint16 {
return c.value
}
// SetInt sets the value as an int, converting it to uint16. Truncates values outside uint16 range (0-65535).
func (c *Uint16) SetInt(value int) {
c.value = uint16(value)
}
// GetInt gets the value as an int, converted from uint16.
func (c *Uint16) GetInt() int {
return int(c.value)
}
// MarshalWrite writes the uint16 value to the provided writer in BigEndian order.
func (c *Uint16) MarshalWrite(w io.Writer) error {
return binary.Write(w, binary.BigEndian, c.value)
}
// UnmarshalRead reads a uint16 value from the provided reader in BigEndian order.
func (c *Uint16) UnmarshalRead(r io.Reader) error {
return binary.Read(r, binary.BigEndian, &c.value)
}
type Uint16s []*Uint16
// Union computes the union of the current Uint16s slice with another Uint16s slice. The result
// contains all unique elements from both slices.
func (s Uint16s) Union(other Uint16s) Uint16s {
valueMap := make(map[uint16]bool)
var result Uint16s
// Add elements from the current Uint16s slice to the result
for _, item := range s {
val := item.Get()
if !valueMap[val] {
valueMap[val] = true
result = append(result, item)
}
}
// Add elements from the other Uint16s slice to the result
for _, item := range other {
val := item.Get()
if !valueMap[val] {
valueMap[val] = true
result = append(result, item)
}
}
return result
}
// Intersection computes the intersection of the current Uint16s slice with another Uint16s
// slice. The result contains only the elements that exist in both slices.
func (s Uint16s) Intersection(other Uint16s) Uint16s {
valueMap := make(map[uint16]bool)
var result Uint16s
// Add all elements from the other Uint16s slice to the map
for _, item := range other {
valueMap[item.Get()] = true
}
// Check for common elements in the current Uint16s slice
for _, item := range s {
val := item.Get()
if valueMap[val] {
result = append(result, item)
}
}
return result
}
// Difference computes the difference of the current Uint16s slice with another Uint16s slice.
// The result contains only the elements that are in the current slice but not in the other
// slice.
func (s Uint16s) Difference(other Uint16s) Uint16s {
valueMap := make(map[uint16]bool)
var result Uint16s
// Mark all elements in the other Uint16s slice
for _, item := range other {
valueMap[item.Get()] = true
}
// Add elements from the current Uint16s slice that are not in the other Uint16s slice
for _, item := range s {
val := item.Get()
if !valueMap[val] {
result = append(result, item)
}
}
return result
}

View File

@@ -0,0 +1,160 @@
package types
import (
"bytes"
"math"
"reflect"
"testing"
"lol.mleku.dev/chk"
"lukechampine.com/frand"
"utils.orly"
)
func TestUint16(t *testing.T) {
// Helper function to generate random 16-bit integers
generateRandomUint16 := func() uint16 {
return uint16(frand.Intn(math.MaxUint16)) // math.MaxUint16 == 65535
}
for i := 0; i < 100; i++ { // Run test 100 times for random values
// Generate a random value
randomUint16 := generateRandomUint16()
randomInt := int(randomUint16)
// Create a new encodedUint16
encodedUint16 := new(Uint16)
// Test UInt16 setter and getter
encodedUint16.Set(randomUint16)
if encodedUint16.Get() != randomUint16 {
t.Fatalf(
"Get mismatch: got %d, expected %d", encodedUint16.Get(),
randomUint16,
)
}
// Test GetInt setter and getter
encodedUint16.SetInt(randomInt)
if encodedUint16.GetInt() != randomInt {
t.Fatalf(
"GetInt mismatch: got %d, expected %d", encodedUint16.GetInt(),
randomInt,
)
}
// Test encoding to []byte and decoding back
bufEnc := new(bytes.Buffer)
// MarshalWrite
err := encodedUint16.MarshalWrite(bufEnc)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
encoded := bufEnc.Bytes()
// Create a copy of encoded bytes before decoding
bufDec := bytes.NewBuffer(encoded)
// Decode back the value
decodedUint16 := new(Uint16)
err = decodedUint16.UnmarshalRead(bufDec)
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
if decodedUint16.Get() != randomUint16 {
t.Fatalf(
"Decoded value mismatch: got %d, expected %d",
decodedUint16.Get(), randomUint16,
)
}
// Compare encoded bytes to ensure correctness
if !utils.FastEqual(encoded, bufEnc.Bytes()) {
t.Fatalf(
"Byte encoding mismatch: got %v, expected %v", bufEnc.Bytes(),
encoded,
)
}
}
}
func TestUint16sSetOperations(t *testing.T) {
// Helper function to create a Uint16 with a specific value
createUint16 := func(value uint16) *Uint16 {
u := &Uint16{}
u.Set(value)
return u
}
// Prepare test data
a := createUint16(1)
b := createUint16(2)
c := createUint16(3)
d := createUint16(4)
e := createUint16(1) // Duplicate of a
// Define slices
set1 := Uint16s{a, b, c} // [1, 2, 3]
set2 := Uint16s{d, e, b} // [4, 1, 2]
expectedUnion := Uint16s{a, b, c, d} // [1, 2, 3, 4]
expectedIntersection := Uint16s{a, b} // [1, 2]
expectedDifference := Uint16s{c} // [3]
// Test Union
t.Run(
"Union", func(t *testing.T) {
result := set1.Union(set2)
if !reflect.DeepEqual(
getUint16Values(result), getUint16Values(expectedUnion),
) {
t.Errorf(
"Union failed: expected %v, got %v",
getUint16Values(expectedUnion), getUint16Values(result),
)
}
},
)
// Test Intersection
t.Run(
"Intersection", func(t *testing.T) {
result := set1.Intersection(set2)
if !reflect.DeepEqual(
getUint16Values(result), getUint16Values(expectedIntersection),
) {
t.Errorf(
"Intersection failed: expected %v, got %v",
getUint16Values(expectedIntersection),
getUint16Values(result),
)
}
},
)
// Test Difference
t.Run(
"Difference", func(t *testing.T) {
result := set1.Difference(set2)
if !reflect.DeepEqual(
getUint16Values(result), getUint16Values(expectedDifference),
) {
t.Errorf(
"Difference failed: expected %v, got %v",
getUint16Values(expectedDifference),
getUint16Values(result),
)
}
},
)
}
// Helper function to extract uint64 values from Uint16s
func getUint16Values(slice Uint16s) []uint16 {
var values []uint16
for _, item := range slice {
values = append(values, item.Get())
}
return values
}

View File

@@ -0,0 +1,154 @@
package types
import (
"errors"
"io"
"lol.mleku.dev/chk"
)
// MaxUint24 is the maximum value of a 24-bit unsigned integer: 2^24 - 1.
const MaxUint24 uint32 = 1<<24 - 1
// Uint24 is a codec for encoding and decoding 24-bit unsigned integers.
type Uint24 struct {
value uint32
}
// Set sets the value as a 24-bit unsigned integer.
// If the value exceeds the maximum allowable value for 24 bits, it returns an error.
func (c *Uint24) Set(value uint32) error {
if value > MaxUint24 {
return errors.New("value exceeds 24-bit range")
}
c.value = value
return nil
}
// Get gets the value as a 24-bit unsigned integer.
func (c *Uint24) Get() uint32 {
return c.value
}
// SetInt sets the value as an int, converting it to a 24-bit unsigned integer.
// If the value is out of the 24-bit range, it returns an error.
func (c *Uint24) SetInt(value int) error {
if value < 0 || uint32(value) > MaxUint24 {
return errors.New("value exceeds 24-bit range")
}
c.value = uint32(value)
return nil
}
// Int gets the value as an int, converted from the 24-bit unsigned integer.
func (c *Uint24) Int() int {
return int(c.value)
}
// MarshalWrite encodes the 24-bit unsigned integer and writes it directly to the provided io.Writer.
// The encoding uses 3 bytes in BigEndian order.
func (c *Uint24) MarshalWrite(w io.Writer) error {
if c.value > MaxUint24 {
return errors.New("value exceeds 24-bit range")
}
// Write the 3 bytes (BigEndian order) directly to the writer
var buf [3]byte
buf[0] = byte((c.value >> 16) & 0xFF) // Most significant byte
buf[1] = byte((c.value >> 8) & 0xFF)
buf[2] = byte(c.value & 0xFF) // Least significant byte
_, err := w.Write(buf[:]) // Write all 3 bytes to the writer
return err
}
// UnmarshalRead reads 3 bytes directly from the provided io.Reader and decodes it into a 24-bit unsigned integer.
func (c *Uint24) UnmarshalRead(r io.Reader) error {
// Read 3 bytes directly from the reader
var buf [3]byte
_, err := io.ReadFull(r, buf[:]) // Ensure exactly 3 bytes are read
if chk.E(err) {
return err
}
// Decode the 3 bytes into a 24-bit unsigned integer
c.value = (uint32(buf[0]) << 16) |
(uint32(buf[1]) << 8) |
uint32(buf[2])
return nil
}
type Uint24s []*Uint24
// Union computes the union of the current Uint24s slice with another Uint24s slice. The result
// contains all unique elements from both slices.
func (s Uint24s) Union(other Uint24s) Uint24s {
valueMap := make(map[uint32]bool)
var result Uint24s
// Add elements from the current Uint24s slice to the result
for _, item := range s {
val := item.Get()
if !valueMap[val] {
valueMap[val] = true
result = append(result, item)
}
}
// Add elements from the other Uint24s slice to the result
for _, item := range other {
val := item.Get()
if !valueMap[val] {
valueMap[val] = true
result = append(result, item)
}
}
return result
}
// Intersection computes the intersection of the current Uint24s slice with another Uint24s
// slice. The result contains only the elements that exist in both slices.
func (s Uint24s) Intersection(other Uint24s) Uint24s {
valueMap := make(map[uint32]bool)
var result Uint24s
// Add all elements from the other Uint24s slice to the map
for _, item := range other {
valueMap[item.Get()] = true
}
// Check for common elements in the current Uint24s slice
for _, item := range s {
val := item.Get()
if valueMap[val] {
result = append(result, item)
}
}
return result
}
// Difference computes the difference of the current Uint24s slice with another Uint24s slice.
// The result contains only the elements that are in the current slice but not in the other
// slice.
func (s Uint24s) Difference(other Uint24s) Uint24s {
valueMap := make(map[uint32]bool)
var result Uint24s
// Mark all elements in the other Uint24s slice
for _, item := range other {
valueMap[item.Get()] = true
}
// Add elements from the current Uint24s slice that are not in the other Uint24s slice
for _, item := range s {
val := item.Get()
if !valueMap[val] {
result = append(result, item)
}
}
return result
}

View File

@@ -0,0 +1,160 @@
package types
import (
"bytes"
"reflect"
"testing"
"lol.mleku.dev/chk"
)
func TestUint24(t *testing.T) {
tests := []struct {
name string
value uint32
expectedErr bool
}{
{"Minimum Value", 0, false},
{"Maximum Value", MaxUint24, false},
{"Value in Range", 8374263, false}, // Example value within the range
{"Value Exceeds Range", MaxUint24 + 1, true}, // Exceeds 24-bit limit
}
for _, tt := range tests {
t.Run(
tt.name, func(t *testing.T) {
codec := new(Uint24)
// Test Set
err := codec.Set(tt.value)
if tt.expectedErr {
if !chk.E(err) {
t.Errorf("expected error but got none")
}
return
} else if chk.E(err) {
t.Errorf("unexpected error: %v", err)
return
}
// Test Get getter
if codec.Get() != tt.value {
t.Errorf(
"Get mismatch: got %d, expected %d", codec.Get(),
tt.value,
)
}
// Test MarshalWrite and UnmarshalRead
buf := new(bytes.Buffer)
// MarshalWrite directly to the buffer
if err := codec.MarshalWrite(buf); chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Validate encoded size is 3 bytes
encoded := buf.Bytes()
if len(encoded) != 3 {
t.Fatalf(
"encoded size mismatch: got %d bytes, expected 3 bytes",
len(encoded),
)
}
// Decode from the buffer
decoded := new(Uint24)
if err := decoded.UnmarshalRead(buf); chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Validate decoded value
if decoded.Get() != tt.value {
t.Errorf(
"Decoded value mismatch: got %d, expected %d",
decoded.Get(), tt.value,
)
}
},
)
}
}
func TestUint24sSetOperations(t *testing.T) {
// Helper function to create a Uint24 with a specific value
createUint24 := func(value uint32) *Uint24 {
u := &Uint24{}
u.Set(value)
return u
}
// Prepare test data
a := createUint24(1)
b := createUint24(2)
c := createUint24(3)
d := createUint24(4)
e := createUint24(1) // Duplicate of a
// Define slices
set1 := Uint24s{a, b, c} // [1, 2, 3]
set2 := Uint24s{d, e, b} // [4, 1, 2]
expectedUnion := Uint24s{a, b, c, d} // [1, 2, 3, 4]
expectedIntersection := Uint24s{a, b} // [1, 2]
expectedDifference := Uint24s{c} // [3]
// Test Union
t.Run(
"Union", func(t *testing.T) {
result := set1.Union(set2)
if !reflect.DeepEqual(
getUint24Values(result), getUint24Values(expectedUnion),
) {
t.Errorf(
"Union failed: expected %v, got %v",
getUint24Values(expectedUnion), getUint24Values(result),
)
}
},
)
// Test Intersection
t.Run(
"Intersection", func(t *testing.T) {
result := set1.Intersection(set2)
if !reflect.DeepEqual(
getUint24Values(result), getUint24Values(expectedIntersection),
) {
t.Errorf(
"Intersection failed: expected %v, got %v",
getUint24Values(expectedIntersection),
getUint24Values(result),
)
}
},
)
// Test Difference
t.Run(
"Difference", func(t *testing.T) {
result := set1.Difference(set2)
if !reflect.DeepEqual(
getUint24Values(result), getUint24Values(expectedDifference),
) {
t.Errorf(
"Difference failed: expected %v, got %v",
getUint24Values(expectedDifference),
getUint24Values(result),
)
}
},
)
}
// Helper function to extract uint64 values from Uint24s
func getUint24Values(slice Uint24s) []uint32 {
var values []uint32
for _, item := range slice {
values = append(values, item.Get())
}
return values
}

View File

@@ -0,0 +1,116 @@
package types
import (
"encoding/binary"
"io"
)
// Uint32 is a codec for encoding and decoding 32-bit unsigned integers.
type Uint32 struct {
value uint32
}
// Set sets the value as a uint32.
func (c *Uint32) Set(value uint32) {
c.value = value
}
// Get gets the value as a uint32.
func (c *Uint32) Get() uint32 {
return c.value
}
// SetInt sets the value as an int, converting it to uint32.
// Values outside the range of uint32 (04294967295) will be truncated.
func (c *Uint32) SetInt(value int) {
c.value = uint32(value)
}
// Int gets the value as an int, converted from uint32.
func (c *Uint32) Int() int {
return int(c.value)
}
// MarshalWrite writes the uint32 value to the provided writer in BigEndian order.
func (c *Uint32) MarshalWrite(w io.Writer) error {
return binary.Write(w, binary.BigEndian, c.value)
}
// UnmarshalRead reads a uint32 value from the provided reader in BigEndian order.
func (c *Uint32) UnmarshalRead(r io.Reader) error {
return binary.Read(r, binary.BigEndian, &c.value)
}
type Uint32s []*Uint32
// Union computes the union of the current Uint32s slice with another Uint32s slice. The result
// contains all unique elements from both slices.
func (s Uint32s) Union(other Uint32s) Uint32s {
valueMap := make(map[uint32]bool)
var result Uint32s
// Add elements from the current Uint32s slice to the result
for _, item := range s {
val := item.Get()
if !valueMap[val] {
valueMap[val] = true
result = append(result, item)
}
}
// Add elements from the other Uint32s slice to the result
for _, item := range other {
val := item.Get()
if !valueMap[val] {
valueMap[val] = true
result = append(result, item)
}
}
return result
}
// Intersection computes the intersection of the current Uint32s slice with another Uint32s
// slice. The result contains only the elements that exist in both slices.
func (s Uint32s) Intersection(other Uint32s) Uint32s {
valueMap := make(map[uint32]bool)
var result Uint32s
// Add all elements from the other Uint32s slice to the map
for _, item := range other {
valueMap[item.Get()] = true
}
// Check for common elements in the current Uint32s slice
for _, item := range s {
val := item.Get()
if valueMap[val] {
result = append(result, item)
}
}
return result
}
// Difference computes the difference of the current Uint32s slice with another Uint32s slice.
// The result contains only the elements that are in the current slice but not in the other
// slice.
func (s Uint32s) Difference(other Uint32s) Uint32s {
valueMap := make(map[uint32]bool)
var result Uint32s
// Mark all elements in the other Uint32s slice
for _, item := range other {
valueMap[item.Get()] = true
}
// Add elements from the current Uint32s slice that are not in the other Uint32s slice
for _, item := range s {
val := item.Get()
if !valueMap[val] {
result = append(result, item)
}
}
return result
}

View File

@@ -0,0 +1,159 @@
package types
import (
"bytes"
"math"
"reflect"
"testing"
"lol.mleku.dev/chk"
"lukechampine.com/frand"
"utils.orly"
)
func TestUint32(t *testing.T) {
// Helper function to generate random 32-bit integers
generateRandomUint32 := func() uint32 {
return uint32(frand.Intn(math.MaxUint32)) // math.MaxUint32 == 4294967295
}
for i := 0; i < 100; i++ { // Run test 100 times for random values
// Generate a random value
randomUint32 := generateRandomUint32()
randomInt := int(randomUint32)
// Create a new codec
codec := new(Uint32)
// Test Uint32 setter and getter
codec.Set(randomUint32)
if codec.Get() != randomUint32 {
t.Fatalf(
"Uint32 mismatch: got %d, expected %d", codec.Get(),
randomUint32,
)
}
// Test GetInt setter and getter
codec.SetInt(randomInt)
if codec.Int() != randomInt {
t.Fatalf(
"GetInt mismatch: got %d, expected %d", codec.Int(), randomInt,
)
}
// Test encoding to []byte and decoding back
bufEnc := new(bytes.Buffer)
// MarshalWrite
err := codec.MarshalWrite(bufEnc)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
encoded := bufEnc.Bytes()
// Create a copy of encoded bytes before decoding
bufDec := bytes.NewBuffer(encoded)
// Decode back the value
decoded := new(Uint32)
err = decoded.UnmarshalRead(bufDec)
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
if decoded.Get() != randomUint32 {
t.Fatalf(
"Decoded value mismatch: got %d, expected %d", decoded.Get(),
randomUint32,
)
}
// Compare encoded bytes to ensure correctness
if !utils.FastEqual(encoded, bufEnc.Bytes()) {
t.Fatalf(
"Byte encoding mismatch: got %v, expected %v", bufEnc.Bytes(),
encoded,
)
}
}
}
func TestUint32sSetOperations(t *testing.T) {
// Helper function to create a Uint32 with a specific value
createUint32 := func(value uint32) *Uint32 {
u := &Uint32{}
u.Set(value)
return u
}
// Prepare test data
a := createUint32(1)
b := createUint32(2)
c := createUint32(3)
d := createUint32(4)
e := createUint32(1) // Duplicate of a
// Define slices
set1 := Uint32s{a, b, c} // [1, 2, 3]
set2 := Uint32s{d, e, b} // [4, 1, 2]
expectedUnion := Uint32s{a, b, c, d} // [1, 2, 3, 4]
expectedIntersection := Uint32s{a, b} // [1, 2]
expectedDifference := Uint32s{c} // [3]
// Test Union
t.Run(
"Union", func(t *testing.T) {
result := set1.Union(set2)
if !reflect.DeepEqual(
getUint32Values(result), getUint32Values(expectedUnion),
) {
t.Errorf(
"Union failed: expected %v, got %v",
getUint32Values(expectedUnion), getUint32Values(result),
)
}
},
)
// Test Intersection
t.Run(
"Intersection", func(t *testing.T) {
result := set1.Intersection(set2)
if !reflect.DeepEqual(
getUint32Values(result), getUint32Values(expectedIntersection),
) {
t.Errorf(
"Intersection failed: expected %v, got %v",
getUint32Values(expectedIntersection),
getUint32Values(result),
)
}
},
)
// Test Difference
t.Run(
"Difference", func(t *testing.T) {
result := set1.Difference(set2)
if !reflect.DeepEqual(
getUint32Values(result), getUint32Values(expectedDifference),
) {
t.Errorf(
"Difference failed: expected %v, got %v",
getUint32Values(expectedDifference),
getUint32Values(result),
)
}
},
)
}
// Helper function to extract uint64 values from Uint32s
func getUint32Values(slice Uint32s) []uint32 {
var values []uint32
for _, item := range slice {
values = append(values, item.Get())
}
return values
}

View File

@@ -0,0 +1,151 @@
package types
import (
"errors"
"io"
"lol.mleku.dev/chk"
)
// MaxUint40 is the maximum value of a 40-bit unsigned integer: 2^40 - 1.
const MaxUint40 uint64 = 1<<40 - 1
// Uint40 is a codec for encoding and decoding 40-bit unsigned integers.
type Uint40 struct{ value uint64 }
// Set sets the value as a 40-bit unsigned integer.
// If the value exceeds the maximum allowable value for 40 bits, it returns an error.
func (c *Uint40) Set(value uint64) error {
if value > MaxUint40 {
return errors.New("value exceeds 40-bit range")
}
c.value = value
return nil
}
// Get gets the value as a 40-bit unsigned integer.
func (c *Uint40) Get() uint64 { return c.value }
// SetInt sets the value as an int, converting it to a 40-bit unsigned integer.
// If the value is out of the 40-bit range, it returns an error.
func (c *Uint40) SetInt(value int) error {
if value < 0 || uint64(value) > MaxUint40 {
return errors.New("value exceeds 40-bit range")
}
c.value = uint64(value)
return nil
}
// GetInt gets the value as an int, converted from the 40-bit unsigned integer.
// Note: If the value exceeds the int range, it will be truncated.
func (c *Uint40) GetInt() int { return int(c.value) }
// MarshalWrite encodes the 40-bit unsigned integer and writes it to the provided writer.
// The encoding uses 5 bytes in BigEndian order.
func (c *Uint40) MarshalWrite(w io.Writer) (err error) {
if c.value > MaxUint40 {
return errors.New("value exceeds 40-bit range")
}
// Buffer for the 5 bytes
buf := make([]byte, 5)
// Write the upper 5 bytes (ignoring the most significant 3 bytes of uint64)
buf[0] = byte((c.value >> 32) & 0xFF) // Most significant byte
buf[1] = byte((c.value >> 24) & 0xFF)
buf[2] = byte((c.value >> 16) & 0xFF)
buf[3] = byte((c.value >> 8) & 0xFF)
buf[4] = byte(c.value & 0xFF) // Least significant byte
_, err = w.Write(buf)
return err
}
// UnmarshalRead reads 5 bytes from the provided reader and decodes it into a 40-bit unsigned integer.
func (c *Uint40) UnmarshalRead(r io.Reader) (err error) {
// Buffer for the 5 bytes
buf := make([]byte, 5)
_, err = r.Read(buf)
if chk.E(err) {
return err
}
// Decode the 5 bytes into a 40-bit unsigned integer
c.value = (uint64(buf[0]) << 32) |
(uint64(buf[1]) << 24) |
(uint64(buf[2]) << 16) |
(uint64(buf[3]) << 8) |
uint64(buf[4])
return nil
}
type Uint40s []*Uint40
// Union computes the union of the current Uint40s slice with another Uint40s slice. The result
// contains all unique elements from both slices.
func (s Uint40s) Union(other Uint40s) Uint40s {
valueMap := make(map[uint64]bool)
var result Uint40s
// Add elements from the current Uint40s slice to the result
for _, item := range s {
val := item.Get()
if !valueMap[val] {
valueMap[val] = true
result = append(result, item)
}
}
// Add elements from the other Uint40s slice to the result
for _, item := range other {
val := item.Get()
if !valueMap[val] {
valueMap[val] = true
result = append(result, item)
}
}
return result
}
// Intersection computes the intersection of the current Uint40s slice with another Uint40s
// slice. The result contains only the elements that exist in both slices.
func (s Uint40s) Intersection(other Uint40s) Uint40s {
valueMap := make(map[uint64]bool)
var result Uint40s
// Add all elements from the other Uint40s slice to the map
for _, item := range other {
valueMap[item.Get()] = true
}
// Check for common elements in the current Uint40s slice
for _, item := range s {
val := item.Get()
if valueMap[val] {
result = append(result, item)
}
}
return result
}
// Difference computes the difference of the current Uint40s slice with another Uint40s slice.
// The result contains only the elements that are in the current slice but not in the other
// slice.
func (s Uint40s) Difference(other Uint40s) Uint40s {
valueMap := make(map[uint64]bool)
var result Uint40s
// Mark all elements in the other Uint40s slice
for _, item := range other {
valueMap[item.Get()] = true
}
// Add elements from the current Uint40s slice that are not in the other Uint40s slice
for _, item := range s {
val := item.Get()
if !valueMap[val] {
result = append(result, item)
}
}
return result
}

View File

@@ -0,0 +1,163 @@
package types
import (
"bytes"
"reflect"
"testing"
"lol.mleku.dev/chk"
)
func TestUint40(t *testing.T) {
// Test cases for Get
tests := []struct {
name string
value uint64
expectedErr bool
}{
{"Minimum Value", 0, false},
{"Maximum Value", MaxUint40, false},
{
"Value in Range", 109951162777, false,
}, // Example value within the range
{"Value Exceeds Range", MaxUint40 + 1, true},
}
for _, tt := range tests {
t.Run(
tt.name, func(t *testing.T) {
codec := new(Uint40)
// Test Set
err := codec.Set(tt.value)
if tt.expectedErr {
if !chk.E(err) {
t.Errorf("expected error but got none")
}
return
} else if chk.E(err) {
t.Errorf("unexpected error: %v", err)
return
}
// Test Get getter
if codec.Get() != tt.value {
t.Errorf(
"Uint40 mismatch: got %d, expected %d", codec.Get(),
tt.value,
)
}
// Test MarshalWrite and UnmarshalRead
buf := new(bytes.Buffer)
// Marshal to a buffer
if err = codec.MarshalWrite(buf); chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Validate encoded size is 5 bytes
encoded := buf.Bytes()
if len(encoded) != 5 {
t.Fatalf(
"encoded size mismatch: got %d bytes, expected 5 bytes",
len(encoded),
)
}
// Decode from the buffer
decoded := new(Uint40)
if err = decoded.UnmarshalRead(buf); chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Validate decoded value
if decoded.Get() != tt.value {
t.Errorf(
"Decoded value mismatch: got %d, expected %d",
decoded.Get(), tt.value,
)
}
},
)
}
}
func TestUint40sSetOperations(t *testing.T) {
// Helper function to create a Uint64 with a specific value
createUint64 := func(value uint64) *Uint40 {
u := &Uint40{}
u.Set(value)
return u
}
// Prepare test data
a := createUint64(1)
b := createUint64(2)
c := createUint64(3)
d := createUint64(4)
e := createUint64(1) // Duplicate of a
// Define slices
set1 := Uint40s{a, b, c} // [1, 2, 3]
set2 := Uint40s{d, e, b} // [4, 1, 2]
expectedUnion := Uint40s{a, b, c, d} // [1, 2, 3, 4]
expectedIntersection := Uint40s{a, b} // [1, 2]
expectedDifference := Uint40s{c} // [3]
// Test Union
t.Run(
"Union", func(t *testing.T) {
result := set1.Union(set2)
if !reflect.DeepEqual(
getUint40Values(result), getUint40Values(expectedUnion),
) {
t.Errorf(
"Union failed: expected %v, got %v",
getUint40Values(expectedUnion), getUint40Values(result),
)
}
},
)
// Test Intersection
t.Run(
"Intersection", func(t *testing.T) {
result := set1.Intersection(set2)
if !reflect.DeepEqual(
getUint40Values(result), getUint40Values(expectedIntersection),
) {
t.Errorf(
"Intersection failed: expected %v, got %v",
getUint40Values(expectedIntersection),
getUint40Values(result),
)
}
},
)
// Test Difference
t.Run(
"Difference", func(t *testing.T) {
result := set1.Difference(set2)
if !reflect.DeepEqual(
getUint40Values(result), getUint40Values(expectedDifference),
) {
t.Errorf(
"Difference failed: expected %v, got %v",
getUint40Values(expectedDifference),
getUint40Values(result),
)
}
},
)
}
// Helper function to extract uint64 values from Uint40s
func getUint40Values(slice Uint40s) []uint64 {
var values []uint64
for _, item := range slice {
values = append(values, item.Get())
}
return values
}

View File

@@ -0,0 +1,117 @@
package types
import (
"encoding/binary"
"io"
)
// Uint64 is a codec for encoding and decoding 64-bit unsigned integers.
type Uint64 struct {
value uint64
}
// Set sets the value as a uint64.
func (c *Uint64) Set(value uint64) {
c.value = value
}
// Get gets the value as a uint64.
func (c *Uint64) Get() uint64 {
return c.value
}
// SetInt sets the value as an int, converting it to uint64.
// Values outside the range of uint64 are truncated.
func (c *Uint64) SetInt(value int) {
c.value = uint64(value)
}
// Int gets the value as an int, converted from uint64. May truncate if the value exceeds the
// range of int.
func (c *Uint64) Int() int {
return int(c.value)
}
// MarshalWrite writes the uint64 value to the provided writer in BigEndian order.
func (c *Uint64) MarshalWrite(w io.Writer) error {
return binary.Write(w, binary.BigEndian, c.value)
}
// UnmarshalRead reads a uint64 value from the provided reader in BigEndian order.
func (c *Uint64) UnmarshalRead(r io.Reader) error {
return binary.Read(r, binary.BigEndian, &c.value)
}
type Uint64s []*Uint64
// Union computes the union of the current Uint64s slice with another Uint64s slice. The result
// contains all unique elements from both slices.
func (s Uint64s) Union(other Uint64s) Uint64s {
valueMap := make(map[uint64]bool)
var result Uint64s
// Add elements from the current Uint64s slice to the result
for _, item := range s {
val := item.Get()
if !valueMap[val] {
valueMap[val] = true
result = append(result, item)
}
}
// Add elements from the other Uint64s slice to the result
for _, item := range other {
val := item.Get()
if !valueMap[val] {
valueMap[val] = true
result = append(result, item)
}
}
return result
}
// Intersection computes the intersection of the current Uint64s slice with another Uint64s
// slice. The result contains only the elements that exist in both slices.
func (s Uint64s) Intersection(other Uint64s) Uint64s {
valueMap := make(map[uint64]bool)
var result Uint64s
// Add all elements from the other Uint64s slice to the map
for _, item := range other {
valueMap[item.Get()] = true
}
// Check for common elements in the current Uint64s slice
for _, item := range s {
val := item.Get()
if valueMap[val] {
result = append(result, item)
}
}
return result
}
// Difference computes the difference of the current Uint64s slice with another Uint64s slice.
// The result contains only the elements that are in the current slice but not in the other
// slice.
func (s Uint64s) Difference(other Uint64s) Uint64s {
valueMap := make(map[uint64]bool)
var result Uint64s
// Mark all elements in the other Uint64s slice
for _, item := range other {
valueMap[item.Get()] = true
}
// Add elements from the current Uint64s slice that are not in the other Uint64s slice
for _, item := range s {
val := item.Get()
if !valueMap[val] {
result = append(result, item)
}
}
return result
}

View File

@@ -0,0 +1,159 @@
package types
import (
"bytes"
"math"
"reflect"
"testing"
"lol.mleku.dev/chk"
"lukechampine.com/frand"
"utils.orly"
)
func TestUint64(t *testing.T) {
// Helper function to generate random 64-bit integers
generateRandomUint64 := func() uint64 {
return frand.Uint64n(math.MaxUint64) // math.MaxUint64 == 18446744073709551615
}
for i := 0; i < 100; i++ { // Run test 100 times for random values
// Generate a random value
randomUint64 := generateRandomUint64()
randomInt := int(randomUint64)
// Create a new codec
codec := new(Uint64)
// Test UInt64 setter and getter
codec.Set(randomUint64)
if codec.Get() != randomUint64 {
t.Fatalf(
"Uint64 mismatch: got %d, expected %d", codec.Get(),
randomUint64,
)
}
// Test GetInt setter and getter
codec.SetInt(randomInt)
if codec.Int() != randomInt {
t.Fatalf(
"GetInt mismatch: got %d, expected %d", codec.Int(), randomInt,
)
}
// Test encoding to []byte and decoding back
bufEnc := new(bytes.Buffer)
// MarshalWrite
err := codec.MarshalWrite(bufEnc)
if chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
encoded := bufEnc.Bytes()
// Create a buffer for decoding
bufDec := bytes.NewBuffer(encoded)
// Decode back the value
decoded := new(Uint64)
err = decoded.UnmarshalRead(bufDec)
if chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
if decoded.Get() != randomUint64 {
t.Fatalf(
"Decoded value mismatch: got %d, expected %d", decoded.Get(),
randomUint64,
)
}
// Compare encoded bytes to ensure correctness
if !utils.FastEqual(encoded, bufEnc.Bytes()) {
t.Fatalf(
"Byte encoding mismatch: got %v, expected %v", bufEnc.Bytes(),
encoded,
)
}
}
}
func TestUint64sSetOperations(t *testing.T) {
// Helper function to create a Uint64 with a specific value
createUint64 := func(value uint64) *Uint64 {
u := &Uint64{}
u.Set(value)
return u
}
// Prepare test data
a := createUint64(1)
b := createUint64(2)
c := createUint64(3)
d := createUint64(4)
e := createUint64(1) // Duplicate of a
// Define slices
set1 := Uint64s{a, b, c} // [1, 2, 3]
set2 := Uint64s{d, e, b} // [4, 1, 2]
expectedUnion := Uint64s{a, b, c, d} // [1, 2, 3, 4]
expectedIntersection := Uint64s{a, b} // [1, 2]
expectedDifference := Uint64s{c} // [3]
// Test Union
t.Run(
"Union", func(t *testing.T) {
result := set1.Union(set2)
if !reflect.DeepEqual(
getUint64Values(result), getUint64Values(expectedUnion),
) {
t.Errorf(
"Union failed: expected %v, got %v",
getUint64Values(expectedUnion), getUint64Values(result),
)
}
},
)
// Test Intersection
t.Run(
"Intersection", func(t *testing.T) {
result := set1.Intersection(set2)
if !reflect.DeepEqual(
getUint64Values(result), getUint64Values(expectedIntersection),
) {
t.Errorf(
"Intersection failed: expected %v, got %v",
getUint64Values(expectedIntersection),
getUint64Values(result),
)
}
},
)
// Test Difference
t.Run(
"Difference", func(t *testing.T) {
result := set1.Difference(set2)
if !reflect.DeepEqual(
getUint64Values(result), getUint64Values(expectedDifference),
) {
t.Errorf(
"Difference failed: expected %v, got %v",
getUint64Values(expectedDifference),
getUint64Values(result),
)
}
},
)
}
// Helper function to extract uint64 values from Uint64s
func getUint64Values(slice Uint64s) []uint64 {
var values []uint64
for _, item := range slice {
values = append(values, item.Get())
}
return values
}

View File

@@ -0,0 +1,71 @@
package types
import (
"bytes"
"io"
"lol.mleku.dev/chk"
)
var zero = []byte{0x00}
type Word struct {
val []byte // Contains only the raw word (without the zero-byte marker)
}
// FromWord stores the word without any modifications
func (w *Word) FromWord(word []byte) {
w.val = word // Only store the raw word
}
// Bytes returns the raw word without any end-of-word marker
func (w *Word) Bytes() []byte {
return w.val
}
// MarshalWrite writes the word to the writer, appending the zero-byte marker
func (w *Word) MarshalWrite(wr io.Writer) (err error) {
if _, err = wr.Write(w.val); chk.E(err) {
return
}
if _, err = wr.Write(zero); chk.E(err) {
return
}
return err
}
// UnmarshalRead reads the word from the reader, stopping at the zero-byte marker
func (w *Word) UnmarshalRead(r io.Reader) error {
buf := new(bytes.Buffer)
tmp := make([]byte, 1)
foundEndMarker := false
// Read bytes until the zero byte is encountered
for {
n, err := r.Read(tmp)
if n > 0 {
if tmp[0] == 0x00 { // Stop on encountering the zero-byte marker
foundEndMarker = true
break
}
buf.WriteByte(tmp[0])
}
if err != nil {
if chk.E(err) {
return err // Handle unexpected errors
}
break
}
}
// Only store the word if we found a valid end marker
if foundEndMarker {
// Make a copy of the bytes to avoid them being zeroed when the buffer is returned to the pool
bytes := buf.Bytes()
w.val = make([]byte, len(bytes))
copy(w.val, bytes)
} else {
w.val = []byte{} // Empty slice if no valid end marker was found
}
return nil
}

View File

@@ -0,0 +1,89 @@
package types_test
import (
"bytes"
"testing"
"database.orly/indexes/types"
"lol.mleku.dev/chk"
"utils.orly"
)
func TestT(t *testing.T) {
// Test cases: each contains inputs, expected serialized output, and expected result after deserialization.
tests := []struct {
word []byte // Input word
expectedBytes []byte // Expected output from Bytes() (raw word)
expectedEncoded []byte // Expected serialized (MarshalWrite) output (word + 0x00)
}{
{[]byte("example"), []byte("example"), []byte("example\x00")},
{[]byte("golang"), []byte("golang"), []byte("golang\x00")},
{[]byte(""), []byte(""), []byte("\x00")}, // Edge case: empty word
{[]byte("123"), []byte("123"), []byte("123\x00")},
}
for _, tt := range tests {
// Create a new object and set the word
ft := new(types.Word)
ft.FromWord(tt.word)
// Ensure Bytes() returns the correct raw word
if got := ft.Bytes(); !utils.FastEqual(tt.expectedBytes, got) {
t.Errorf(
"FromWord/Bytes failed: expected %q, got %q", tt.expectedBytes,
got,
)
}
// Test MarshalWrite
var buf bytes.Buffer
if err := ft.MarshalWrite(&buf); chk.E(err) {
t.Fatalf("MarshalWrite failed: %v", err)
}
// Ensure the serialized output matches expectedEncoded
if got := buf.Bytes(); !utils.FastEqual(tt.expectedEncoded, got) {
t.Errorf(
"MarshalWrite failed: expected %q, got %q", tt.expectedEncoded,
got,
)
}
// Test UnmarshalRead
newFt := new(types.Word)
// Create a new reader from the buffer to reset the read position
reader := bytes.NewReader(buf.Bytes())
if err := newFt.UnmarshalRead(reader); chk.E(err) {
t.Fatalf("UnmarshalRead failed: %v", err)
}
// Ensure the word after decoding matches the original word
if got := newFt.Bytes(); !utils.FastEqual(tt.expectedBytes, got) {
t.Errorf(
"UnmarshalRead failed: expected %q, got %q", tt.expectedBytes,
got,
)
}
}
}
func TestUnmarshalReadHandlesMissingZeroByte(t *testing.T) {
// Special case: what happens if the zero-byte marker is missing?
data := []byte("incomplete") // No zero-byte at the end
reader := bytes.NewReader(data)
ft := new(types.Word)
err := ft.UnmarshalRead(reader)
// Expect an EOF or similar handling
if !chk.E(err) {
t.Errorf("UnmarshalRead should fail gracefully on missing zero-byte, but it didn't")
}
// Ensure no data is stored in ft.val if no valid end-marker was encountered
if got := ft.Bytes(); len(got) != 0 {
t.Errorf(
"UnmarshalRead stored incomplete data: got %q, expected empty", got,
)
}
}