package hashcash_test import ( "crypto/sha256" "encoding/hex" "testing" "git.eeqj.de/sneak/neoirc/internal/hashcash" ) const ( testChannel = "#general" testBodyText = `["hello world"]` ) func testBodyHash() string { hash := sha256.Sum256([]byte(testBodyText)) return hex.EncodeToString(hash[:]) } func TestChannelValidateHappyPath(t *testing.T) { t.Parallel() validator := hashcash.NewChannelValidator() bodyHash := testBodyHash() stamp := hashcash.MintChannelStamp( testBits, testChannel, bodyHash, ) err := validator.ValidateStamp( stamp, testBits, testChannel, bodyHash, ) if err != nil { t.Fatalf("valid channel stamp rejected: %v", err) } } func TestChannelValidateWrongChannel(t *testing.T) { t.Parallel() validator := hashcash.NewChannelValidator() bodyHash := testBodyHash() stamp := hashcash.MintChannelStamp( testBits, testChannel, bodyHash, ) err := validator.ValidateStamp( stamp, testBits, "#other", bodyHash, ) if err == nil { t.Fatal("expected channel mismatch error") } } func TestChannelValidateWrongBodyHash(t *testing.T) { t.Parallel() validator := hashcash.NewChannelValidator() bodyHash := testBodyHash() stamp := hashcash.MintChannelStamp( testBits, testChannel, bodyHash, ) wrongHash := sha256.Sum256([]byte("different body")) wrongBodyHash := hex.EncodeToString(wrongHash[:]) err := validator.ValidateStamp( stamp, testBits, testChannel, wrongBodyHash, ) if err == nil { t.Fatal("expected body hash mismatch error") } } func TestChannelValidateInsufficientBits(t *testing.T) { t.Parallel() validator := hashcash.NewChannelValidator() bodyHash := testBodyHash() // Mint with 2 bits but require 4. stamp := hashcash.MintChannelStamp( testBits, testChannel, bodyHash, ) err := validator.ValidateStamp( stamp, 4, testChannel, bodyHash, ) if err == nil { t.Fatal("expected insufficient bits error") } } func TestChannelValidateZeroBitsSkips(t *testing.T) { t.Parallel() validator := hashcash.NewChannelValidator() err := validator.ValidateStamp( "garbage", 0, "#ch", "abc", ) if err != nil { t.Fatalf("zero bits should skip: %v", err) } } func TestChannelValidateBadFormat(t *testing.T) { t.Parallel() validator := hashcash.NewChannelValidator() err := validator.ValidateStamp( "not:valid", testBits, testChannel, "abc", ) if err == nil { t.Fatal("expected bad format error") } } func TestChannelValidateBadVersion(t *testing.T) { t.Parallel() validator := hashcash.NewChannelValidator() bodyHash := testBodyHash() stamp := "2:2:260317:#general:" + bodyHash + ":counter" err := validator.ValidateStamp( stamp, testBits, testChannel, bodyHash, ) if err == nil { t.Fatal("expected bad version error") } } func TestChannelValidateExpiredStamp(t *testing.T) { t.Parallel() validator := hashcash.NewChannelValidator() bodyHash := testBodyHash() // Mint with a very old date by manually constructing. stamp := mintStampWithDate( t, testBits, testChannel, "200101", ) err := validator.ValidateStamp( stamp, testBits, testChannel, bodyHash, ) if err == nil { t.Fatal("expected expired stamp error") } } func TestChannelValidateMissingBodyHash(t *testing.T) { t.Parallel() validator := hashcash.NewChannelValidator() bodyHash := testBodyHash() // Construct a stamp with empty body hash field. stamp := mintStampWithDate( t, testBits, testChannel, todayDate(), ) // This uses the session-style stamp which has empty // ext field — body hash is missing. err := validator.ValidateStamp( stamp, testBits, testChannel, bodyHash, ) if err == nil { t.Fatal("expected missing body hash error") } } func TestBodyHash(t *testing.T) { t.Parallel() body := []byte(`["hello world"]`) bodyHash := hashcash.BodyHash(body) if len(bodyHash) != 64 { t.Fatalf( "expected 64-char hex hash, got %d", len(bodyHash), ) } // Same input should produce same hash. bodyHash2 := hashcash.BodyHash(body) if bodyHash != bodyHash2 { t.Fatal("body hash not deterministic") } // Different input should produce different hash. bodyHash3 := hashcash.BodyHash([]byte("different")) if bodyHash == bodyHash3 { t.Fatal("different inputs produced same hash") } } func TestStampHash(t *testing.T) { t.Parallel() hash1 := hashcash.StampHash("stamp1") hash2 := hashcash.StampHash("stamp2") if hash1 == hash2 { t.Fatal("different stamps produced same hash") } // Same input should be deterministic. hash1b := hashcash.StampHash("stamp1") if hash1 != hash1b { t.Fatal("stamp hash not deterministic") } } func TestMintChannelStamp(t *testing.T) { t.Parallel() bodyHash := testBodyHash() stamp := hashcash.MintChannelStamp( testBits, testChannel, bodyHash, ) if stamp == "" { t.Fatal("expected non-empty stamp") } // Validate the minted stamp. validator := hashcash.NewChannelValidator() err := validator.ValidateStamp( stamp, testBits, testChannel, bodyHash, ) if err != nil { t.Fatalf("minted stamp failed validation: %v", err) } }