179 lines
4.7 KiB
Go
179 lines
4.7 KiB
Go
package sha1x_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"code.yun.ink/pkg/encryptx/sha1x"
|
|
)
|
|
|
|
// 测试向量来源:FIPS 180-1 / RFC 3174 附录 A,并经 Python 3 hashlib 独立复算确认。
|
|
var vectors = []struct {
|
|
name string
|
|
input string
|
|
want string
|
|
}{
|
|
{"空串", "", "da39a3ee5e6b4b0d3255bfef95601890afd80709"},
|
|
{"abc", "abc", "a9993e364706816aba3e25717850c26c9cd0d89d"},
|
|
{"message digest", "message digest", "c12252ceda8be8994d5fa0290a47231c1d16aae3"},
|
|
{"The quick brown fox jumps over the lazy dog", "The quick brown fox jumps over the lazy dog", "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"},
|
|
}
|
|
|
|
type failingReader struct{}
|
|
|
|
func (failingReader) Read([]byte) (int, error) { return 0, errors.New("模拟读取失败") }
|
|
|
|
func TestConstants(t *testing.T) {
|
|
if sha1x.Size != 20 {
|
|
t.Fatalf("Size = %d, 期望 20", sha1x.Size)
|
|
}
|
|
if sha1x.BlockSize != 64 {
|
|
t.Fatalf("BlockSize = %d, 期望 64", sha1x.BlockSize)
|
|
}
|
|
}
|
|
|
|
func TestVectors(t *testing.T) {
|
|
for _, v := range vectors {
|
|
t.Run(v.name, func(t *testing.T) {
|
|
data := []byte(v.input)
|
|
sum := sha1x.Sum(data)
|
|
if len(sum) != sha1x.Size {
|
|
t.Fatalf("Sum 长度 = %d, 期望 %d", len(sum), sha1x.Size)
|
|
}
|
|
if got := hex.EncodeToString(sum); got != v.want {
|
|
t.Errorf("Sum = %s, 期望 %s", got, v.want)
|
|
}
|
|
if got := sha1x.Hex(data); got != v.want {
|
|
t.Errorf("Hex = %s, 期望 %s", got, v.want)
|
|
}
|
|
if want := base64.StdEncoding.EncodeToString(sum); sha1x.Base64(data) != want {
|
|
t.Errorf("Base64 = %s, 期望 %s", sha1x.Base64(data), want)
|
|
}
|
|
h := sha1x.New()
|
|
if _, err := h.Write(data); err != nil {
|
|
t.Fatalf("Write 失败: %v", err)
|
|
}
|
|
if got := hex.EncodeToString(h.Sum(nil)); got != v.want {
|
|
t.Errorf("New+Write = %s, 期望 %s", got, v.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStreamingMatchesSum(t *testing.T) {
|
|
data := []byte(strings.Repeat("encryptx-sha1-", 100))
|
|
h := sha1x.New()
|
|
for i := 0; i < len(data); i += 13 {
|
|
end := i + 13
|
|
if end > len(data) {
|
|
end = len(data)
|
|
}
|
|
if _, err := h.Write(data[i:end]); err != nil {
|
|
t.Fatalf("Write 失败: %v", err)
|
|
}
|
|
}
|
|
if got, want := h.Sum(nil), sha1x.Sum(data); !bytes.Equal(got, want) {
|
|
t.Errorf("分块写入 = %x, 期望 %x", got, want)
|
|
}
|
|
}
|
|
|
|
func TestReaderConsistency(t *testing.T) {
|
|
const s = "encryptx 一致性检查"
|
|
sum, err := sha1x.SumReader(strings.NewReader(s))
|
|
if err != nil {
|
|
t.Fatalf("SumReader 失败: %v", err)
|
|
}
|
|
if want := sha1x.Sum([]byte(s)); !bytes.Equal(sum, want) {
|
|
t.Errorf("SumReader = %x, 期望 %x", sum, want)
|
|
}
|
|
hexStr, err := sha1x.HexReader(strings.NewReader(s))
|
|
if err != nil {
|
|
t.Fatalf("HexReader 失败: %v", err)
|
|
}
|
|
if want := sha1x.Hex([]byte(s)); hexStr != want {
|
|
t.Errorf("HexReader = %s, 期望 %s", hexStr, want)
|
|
}
|
|
}
|
|
|
|
func TestReaderErrors(t *testing.T) {
|
|
if _, err := sha1x.SumReader(nil); err == nil {
|
|
t.Fatal("nil 读取器应返回 error")
|
|
}
|
|
if _, err := sha1x.HexReader(nil); err == nil {
|
|
t.Fatal("nil 读取器应返回 error")
|
|
}
|
|
if _, err := sha1x.SumReader(failingReader{}); err == nil {
|
|
t.Fatal("读取失败时应返回 error")
|
|
}
|
|
}
|
|
|
|
func TestHexFile(t *testing.T) {
|
|
dir := t.TempDir()
|
|
content := []byte("文件内容 file content\n")
|
|
path := filepath.Join(dir, "sample.bin")
|
|
if err := os.WriteFile(path, content, 0o600); err != nil {
|
|
t.Fatalf("写入测试文件失败: %v", err)
|
|
}
|
|
got, err := sha1x.HexFile(path)
|
|
if err != nil {
|
|
t.Fatalf("HexFile 失败: %v", err)
|
|
}
|
|
if want := sha1x.Hex(content); got != want {
|
|
t.Errorf("HexFile = %s, 期望 %s", got, want)
|
|
}
|
|
}
|
|
|
|
func TestHexFileErrors(t *testing.T) {
|
|
if _, err := sha1x.HexFile(filepath.Join(t.TempDir(), "不存在.bin")); err == nil {
|
|
t.Fatal("不存在的文件应返回 error")
|
|
}
|
|
if _, err := sha1x.HexFile(""); err == nil {
|
|
t.Fatal("空路径应返回 error")
|
|
}
|
|
if _, err := sha1x.HexFile(t.TempDir()); err == nil {
|
|
t.Fatal("目录路径应返回 error")
|
|
}
|
|
}
|
|
|
|
func TestLargeInput(t *testing.T) {
|
|
data := largeData(1 << 20)
|
|
want := sha1x.Hex(data)
|
|
if got := sha1x.Hex(data); got != want {
|
|
t.Errorf("重复计算结果不一致: %s vs %s", got, want)
|
|
}
|
|
|
|
got, err := sha1x.HexReader(bytes.NewReader(data))
|
|
if err != nil {
|
|
t.Fatalf("HexReader 失败: %v", err)
|
|
}
|
|
if got != want {
|
|
t.Errorf("HexReader = %s, 期望 %s", got, want)
|
|
}
|
|
|
|
h := sha1x.New()
|
|
if _, err := h.Write(data[:1<<19]); err != nil {
|
|
t.Fatalf("Write 失败: %v", err)
|
|
}
|
|
if _, err := h.Write(data[1<<19:]); err != nil {
|
|
t.Fatalf("Write 失败: %v", err)
|
|
}
|
|
if got := hex.EncodeToString(h.Sum(nil)); got != want {
|
|
t.Errorf("1MiB 分块 = %s, 期望 %s", got, want)
|
|
}
|
|
}
|
|
|
|
// largeData 生成确定性的 n 字节数据。
|
|
func largeData(n int) []byte {
|
|
b := make([]byte, n)
|
|
for i := range b {
|
|
b[i] = byte(i*31 + i/7)
|
|
}
|
|
return b
|
|
}
|