package hashx import ( "bytes" "crypto/md5" "encoding/hex" "os" "path/filepath" "testing" ) func TestSha1StrMatchesSha1(t *testing.T) { got := Sha1Str([]byte("abc")) const want = "a9993e364706816aba3e25717850c26c9cd0d89d" if got != want { t.Fatalf("Sha1Str mismatch, got %s want %s", got, want) } } func TestSM3AndCRC32A(t *testing.T) { if len(SM3([]byte("abc"))) != 32 { t.Fatalf("SM3 digest size must be 32") } if Crc32AStr([]byte("123456789")) != "181989fc" { t.Fatalf("Crc32AStr mismatch") } if CheckCRC32A([]byte("123456789")) != 0x181989fc { t.Fatalf("CheckCRC32A mismatch") } } func TestSumAllUnknownMethodIgnored(t *testing.T) { res, err := SumAll([]byte("abc"), []string{"sha1", "unknown"}) if err != nil { t.Fatalf("SumAll returned error: %v", err) } if _, ok := res["sha1"]; !ok { t.Fatalf("expected sha1 in result") } if _, ok := res["unknown"]; ok { t.Fatalf("unknown method should be ignored") } } func TestFileSumAndFileSumAll(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "sum.txt") data := []byte("hash-file-content") if err := os.WriteFile(path, data, 0o644); err != nil { t.Fatalf("WriteFile failed: %v", err) } calls := 0 h, err := FileSum(path, "md5", func(float64) { calls++ }) if err != nil { t.Fatalf("FileSum failed: %v", err) } expected := md5.Sum(data) if h != hex.EncodeToString(expected[:]) { t.Fatalf("md5 mismatch, got %s want %s", h, hex.EncodeToString(expected[:])) } if calls == 0 { t.Fatalf("progress callback should be called") } all, err := FileSumAll(path, []string{"sha1", "crc32", "unknown"}, nil) if err != nil { t.Fatalf("FileSumAll failed: %v", err) } if _, ok := all["sha1"]; !ok { t.Fatalf("expected sha1 in FileSumAll") } if _, ok := all["crc32"]; !ok { t.Fatalf("expected crc32 in FileSumAll") } if _, ok := all["unknown"]; ok { t.Fatalf("unknown method should not appear") } } func TestFileSumUnsupportedMethod(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "sum.txt") if err := os.WriteFile(path, []byte("x"), 0o644); err != nil { t.Fatalf("WriteFile failed: %v", err) } if _, err := FileSum(path, "not-support", nil); err == nil { t.Fatalf("expected unsupported method error") } } func TestPBKDF2SHA256Vector(t *testing.T) { got, err := DerivePBKDF2SHA256Key("password", []byte("salt"), 1, 32) if err != nil { t.Fatalf("DerivePBKDF2SHA256Key failed: %v", err) } const want = "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b" if hex.EncodeToString(got) != want { t.Fatalf("pbkdf2-sha256 vector mismatch: got %x want %s", got, want) } } func TestPBKDF2AndArgon2Deterministic(t *testing.T) { a, err := DerivePBKDF2SHA512Key("password", []byte("salt"), 1000, 32) if err != nil { t.Fatalf("DerivePBKDF2SHA512Key failed: %v", err) } b, err := DerivePBKDF2SHA512Key("password", []byte("salt"), 1000, 32) if err != nil { t.Fatalf("DerivePBKDF2SHA512Key failed: %v", err) } if !bytes.Equal(a, b) { t.Fatalf("pbkdf2-sha512 must be deterministic") } params := Argon2Params{Time: 1, Memory: 32 * 1024, Threads: 1, KeyLen: 32} argA, err := DeriveArgon2idKey("password", []byte("salt-salt"), params) if err != nil { t.Fatalf("DeriveArgon2idKey failed: %v", err) } argB, err := DeriveArgon2idKey("password", []byte("salt-salt"), params) if err != nil { t.Fatalf("DeriveArgon2idKey failed: %v", err) } if !bytes.Equal(argA, argB) { t.Fatalf("argon2id must be deterministic") } } func TestKDFInvalidParams(t *testing.T) { if _, err := DerivePBKDF2SHA256Key("password", nil, 1, 32); err == nil { t.Fatalf("expected pbkdf2 salt error") } if _, err := DerivePBKDF2SHA256Key("password", []byte("salt"), 0, 32); err == nil { t.Fatalf("expected pbkdf2 iterations error") } if _, err := DeriveArgon2idKey("password", []byte("salt"), Argon2Params{}); err == nil { t.Fatalf("expected argon2 params error") } }