commit 1cbaf88b292f37da6166d6013ff053fb48325eb6 Author: tursom Date: Tue Aug 1 15:32:05 2023 +0800 init commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36bdac5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,181 @@ +### Intellij template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij+all template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Go template +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + diff --git a/.idea/$PROJECT_FILE$ b/.idea/$PROJECT_FILE$ new file mode 100644 index 0000000..58b7e3e --- /dev/null +++ b/.idea/$PROJECT_FILE$ @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..4d5d588 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..2c7451d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/assert/assertion.go b/assert/assertion.go new file mode 100644 index 0000000..18a1787 --- /dev/null +++ b/assert/assertion.go @@ -0,0 +1,12 @@ +package assert + +import ( + "reflect" + "testing" +) + +func Equals[T any](t *testing.T, got, want T) { + if !reflect.DeepEqual(got, want) { + errorf(t, "%s got %v, but want %v", t.Name(), got, want) + } +} diff --git a/assert/log.go b/assert/log.go new file mode 100644 index 0000000..7bba61d --- /dev/null +++ b/assert/log.go @@ -0,0 +1,19 @@ +package assert + +import ( + "fmt" + "testing" + + _ "unsafe" +) + +// 指针接收器 +// +//go:linkname logDepth testing.(*common).logDepth +//go:nosplit +func logDepth(_ *testing.T, s string, depth int) + +func errorf(t *testing.T, format string, args ...any) { + logDepth(t, fmt.Sprintf(format, args...), 3) + t.Fail() +} diff --git a/checksum/adler32.go b/checksum/adler32.go new file mode 100644 index 0000000..55d40eb --- /dev/null +++ b/checksum/adler32.go @@ -0,0 +1,32 @@ +package checksum + +import ( + "hash" + "hash/adler32" +) + +type ( + Adler32 struct { + d hash.Hash + } +) + +func (m *Adler32) String() string { + return "adler32" +} + +func (m *Adler32) Append(data []byte) { + if m.d == nil { + m.d = adler32.New() + } + + m.d.Write(data) +} + +func (m *Adler32) Finish() []byte { + if m.d == nil { + m.d = adler32.New() + } + + return m.d.Sum(nil) +} diff --git a/checksum/adler32_test.go b/checksum/adler32_test.go new file mode 100644 index 0000000..005c910 --- /dev/null +++ b/checksum/adler32_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/adler32" + "testing" +) + +func TestAdler32_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Adler32) + want []byte + }{ + { + "nil", + fields{}, + nil, + adler32.New().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Adler32) { + m.Append([]byte("hello")) + }, + adler32sum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Adler32{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func adler32sum(b []byte) []byte { + h := adler32.New() + h.Write(b) + return h.Sum(nil) +} + +func TestAdler32_String(t *testing.T) { + assert.Equals(t, (&Adler32{}).String(), "adler32") +} diff --git a/checksum/crc.go b/checksum/crc.go new file mode 100644 index 0000000..464abd6 --- /dev/null +++ b/checksum/crc.go @@ -0,0 +1,134 @@ +package checksum + +import ( + "hash" + "hash/crc32" + "hash/crc64" +) + +var ( + IEEETable = crc32.IEEETable + CastagnoliTable = crc32.MakeTable(crc32.Castagnoli) + KoopmanTable = crc32.MakeTable(crc32.Koopman) + + ISOTable = crc64.MakeTable(crc64.ISO) + ECMATable = crc64.MakeTable(crc64.ECMA) +) + +type ( + Crc32Ieee struct { + d hash.Hash + } + Crc32Castagnoli struct { + d hash.Hash + } + Crc32Koopman struct { + d hash.Hash + } + Crc64Iso struct { + d hash.Hash + } + Crc64Ecma struct { + d hash.Hash + } +) + +func (m *Crc32Ieee) String() string { + return "crc32ieee" +} + +func (m *Crc32Ieee) Append(data []byte) { + if m.d == nil { + m.d = crc32.New(IEEETable) + } + + m.d.Write(data) +} + +func (m *Crc32Ieee) Finish() []byte { + if m.d == nil { + m.d = crc32.New(IEEETable) + } + + return m.d.Sum(nil) +} + +func (m *Crc32Castagnoli) String() string { + return "crc32castagnoli" +} + +func (m *Crc32Castagnoli) Append(data []byte) { + if m.d == nil { + m.d = crc32.New(CastagnoliTable) + } + + m.d.Write(data) +} + +func (m *Crc32Castagnoli) Finish() []byte { + if m.d == nil { + m.d = crc32.New(CastagnoliTable) + } + + return m.d.Sum(nil) +} + +func (m *Crc32Koopman) String() string { + return "crc32koopman" +} + +func (m *Crc32Koopman) Append(data []byte) { + if m.d == nil { + m.d = crc32.New(KoopmanTable) + } + + m.d.Write(data) +} + +func (m *Crc32Koopman) Finish() []byte { + if m.d == nil { + m.d = crc32.New(KoopmanTable) + } + + return m.d.Sum(nil) +} + +func (m *Crc64Iso) String() string { + return "crc64iso" +} + +func (m *Crc64Iso) Append(data []byte) { + if m.d == nil { + m.d = crc64.New(ISOTable) + } + + m.d.Write(data) +} + +func (m *Crc64Iso) Finish() []byte { + if m.d == nil { + m.d = crc64.New(ISOTable) + } + + return m.d.Sum(nil) +} + +func (m *Crc64Ecma) String() string { + return "crc64ecma" +} + +func (m *Crc64Ecma) Append(data []byte) { + if m.d == nil { + m.d = crc64.New(ECMATable) + } + + m.d.Write(data) +} + +func (m *Crc64Ecma) Finish() []byte { + if m.d == nil { + m.d = crc64.New(ECMATable) + } + + return m.d.Sum(nil) +} diff --git a/checksum/crc32castagnoli_test.go b/checksum/crc32castagnoli_test.go new file mode 100644 index 0000000..c3767ed --- /dev/null +++ b/checksum/crc32castagnoli_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/crc32" + "testing" +) + +func TestCrc32Castagnoli_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Crc32Castagnoli) + want []byte + }{ + { + "nil", + fields{}, + nil, + crc32.New(CastagnoliTable).Sum(nil), + }, + { + "hello", + fields{}, + func(m *Crc32Castagnoli) { + m.Append([]byte("hello")) + }, + crc32CastagnoliSum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Crc32Castagnoli{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func crc32CastagnoliSum(b []byte) []byte { + h := crc32.New(CastagnoliTable) + h.Write(b) + return h.Sum(nil) +} + +func TestCrc32Castagnoli_String(t *testing.T) { + assert.Equals(t, (&Crc32Castagnoli{}).String(), "crc32castagnoli") +} diff --git a/checksum/crc32ieee_test.go b/checksum/crc32ieee_test.go new file mode 100644 index 0000000..6d42ac0 --- /dev/null +++ b/checksum/crc32ieee_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/crc32" + "testing" +) + +func TestCrc32Ieee_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Crc32Ieee) + want []byte + }{ + { + "nil", + fields{}, + nil, + crc32.New(IEEETable).Sum(nil), + }, + { + "hello", + fields{}, + func(m *Crc32Ieee) { + m.Append([]byte("hello")) + }, + crc32Ieeesum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Crc32Ieee{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func crc32Ieeesum(b []byte) []byte { + h := crc32.New(crc32.IEEETable) + h.Write(b) + return h.Sum(nil) +} + +func TestCrc32Ieee_String(t *testing.T) { + assert.Equals(t, (&Crc32Ieee{}).String(), "crc32ieee") +} diff --git a/checksum/crc32koopman_test.go b/checksum/crc32koopman_test.go new file mode 100644 index 0000000..d33569a --- /dev/null +++ b/checksum/crc32koopman_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/crc32" + "testing" +) + +func TestCrc32Koopman_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Crc32Koopman) + want []byte + }{ + { + "nil", + fields{}, + nil, + crc32.New(KoopmanTable).Sum(nil), + }, + { + "hello", + fields{}, + func(m *Crc32Koopman) { + m.Append([]byte("hello")) + }, + crc32KoopmanSum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Crc32Koopman{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func crc32KoopmanSum(b []byte) []byte { + h := crc32.New(KoopmanTable) + h.Write(b) + return h.Sum(nil) +} + +func TestCrc32Koopman_String(t *testing.T) { + assert.Equals(t, (&Crc32Koopman{}).String(), "crc32koopman") +} diff --git a/checksum/crc64ecma_test.go b/checksum/crc64ecma_test.go new file mode 100644 index 0000000..2fda023 --- /dev/null +++ b/checksum/crc64ecma_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/crc64" + "testing" +) + +func TestCrc64Ecma_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Crc64Ecma) + want []byte + }{ + { + "nil", + fields{}, + nil, + crc64.New(ECMATable).Sum(nil), + }, + { + "hello", + fields{}, + func(m *Crc64Ecma) { + m.Append([]byte("hello")) + }, + crc64EcmaSum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Crc64Ecma{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func crc64EcmaSum(b []byte) []byte { + h := crc64.New(ECMATable) + h.Write(b) + return h.Sum(nil) +} + +func TestCrc64Ecma_String(t *testing.T) { + assert.Equals(t, (&Crc64Ecma{}).String(), "crc64ecma") +} diff --git a/checksum/crc64iso_test.go b/checksum/crc64iso_test.go new file mode 100644 index 0000000..d7e67d0 --- /dev/null +++ b/checksum/crc64iso_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/crc64" + "testing" +) + +func TestCrc64Iso_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Crc64Iso) + want []byte + }{ + { + "nil", + fields{}, + nil, + crc64.New(ISOTable).Sum(nil), + }, + { + "hello", + fields{}, + func(m *Crc64Iso) { + m.Append([]byte("hello")) + }, + crc64IsoSum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Crc64Iso{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func crc64IsoSum(b []byte) []byte { + h := crc64.New(ISOTable) + h.Write(b) + return h.Sum(nil) +} + +func TestCrc64Iso_String(t *testing.T) { + assert.Equals(t, (&Crc64Iso{}).String(), "crc64iso") +} diff --git a/checksum/crc_test.go b/checksum/crc_test.go new file mode 100644 index 0000000..59dc7d8 --- /dev/null +++ b/checksum/crc_test.go @@ -0,0 +1,28 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash/crc32" + "hash/crc64" + "testing" +) + +func TestIEEETable(t *testing.T) { + assert.Equals(t, IEEETable, crc32.IEEETable) +} + +func TestCastagnoliTable(t *testing.T) { + assert.Equals(t, CastagnoliTable, crc32.MakeTable(crc32.Castagnoli)) +} + +func TestKoopmanTable(t *testing.T) { + assert.Equals(t, KoopmanTable, crc32.MakeTable(crc32.Koopman)) +} + +func TestISOTable(t *testing.T) { + assert.Equals(t, ISOTable, crc64.MakeTable(crc64.ISO)) +} + +func TestECMATable(t *testing.T) { + assert.Equals(t, ECMATable, crc64.MakeTable(crc64.ECMA)) +} diff --git a/checksum/def.go b/checksum/def.go new file mode 100644 index 0000000..b7fe54f --- /dev/null +++ b/checksum/def.go @@ -0,0 +1,11 @@ +package checksum + +import "fmt" + +type ( + Func interface { + fmt.Stringer + Append(data []byte) + Finish() []byte + } +) diff --git a/checksum/fnc128_test.go b/checksum/fnc128_test.go new file mode 100644 index 0000000..c6c8de0 --- /dev/null +++ b/checksum/fnc128_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/fnv" + "testing" +) + +func TestFnv128_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Fnv128) + want []byte + }{ + { + "nil", + fields{}, + nil, + fnv.New128().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Fnv128) { + m.Append([]byte("hello")) + }, + fnv128Sum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Fnv128{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func fnv128Sum(b []byte) []byte { + h := fnv.New128() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestFnv128_String(t *testing.T) { + assert.Equals(t, (&Fnv128{}).String(), "fnv128") +} diff --git a/checksum/fnc128a_test.go b/checksum/fnc128a_test.go new file mode 100644 index 0000000..ce3d786 --- /dev/null +++ b/checksum/fnc128a_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/fnv" + "testing" +) + +func TestFnv128a_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Fnv128a) + want []byte + }{ + { + "nil", + fields{}, + nil, + fnv.New128a().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Fnv128a) { + m.Append([]byte("hello")) + }, + fnv128aSum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Fnv128a{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func fnv128aSum(b []byte) []byte { + h := fnv.New128a() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestFnv128a_String(t *testing.T) { + assert.Equals(t, (&Fnv128a{}).String(), "fnv128a") +} diff --git a/checksum/fnc32_test.go b/checksum/fnc32_test.go new file mode 100644 index 0000000..401d070 --- /dev/null +++ b/checksum/fnc32_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/fnv" + "testing" +) + +func TestFnv32_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Fnv32) + want []byte + }{ + { + "nil", + fields{}, + nil, + fnv.New32().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Fnv32) { + m.Append([]byte("hello")) + }, + fnv32Sum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Fnv32{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func fnv32Sum(b []byte) []byte { + h := fnv.New32() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestFnv32_String(t *testing.T) { + assert.Equals(t, (&Fnv32{}).String(), "fnv32") +} diff --git a/checksum/fnc32a_test.go b/checksum/fnc32a_test.go new file mode 100644 index 0000000..5b32121 --- /dev/null +++ b/checksum/fnc32a_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/fnv" + "testing" +) + +func TestFnv32a_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Fnv32a) + want []byte + }{ + { + "nil", + fields{}, + nil, + fnv.New32a().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Fnv32a) { + m.Append([]byte("hello")) + }, + fnv32aSum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Fnv32a{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func fnv32aSum(b []byte) []byte { + h := fnv.New32a() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestFnv32a_String(t *testing.T) { + assert.Equals(t, (&Fnv32a{}).String(), "fnv32a") +} diff --git a/checksum/fnc64_test.go b/checksum/fnc64_test.go new file mode 100644 index 0000000..4444153 --- /dev/null +++ b/checksum/fnc64_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/fnv" + "testing" +) + +func TestFnv64_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Fnv64) + want []byte + }{ + { + "nil", + fields{}, + nil, + fnv.New64().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Fnv64) { + m.Append([]byte("hello")) + }, + fnv64Sum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Fnv64{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func fnv64Sum(b []byte) []byte { + h := fnv.New64() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestFnv64_String(t *testing.T) { + assert.Equals(t, (&Fnv64{}).String(), "fnv64") +} diff --git a/checksum/fnc64a_test.go b/checksum/fnc64a_test.go new file mode 100644 index 0000000..773aa90 --- /dev/null +++ b/checksum/fnc64a_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/tursom/checksum/assert" + "hash" + "hash/fnv" + "testing" +) + +func TestFnv64a_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Fnv64a) + want []byte + }{ + { + "nil", + fields{}, + nil, + fnv.New64a().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Fnv64a) { + m.Append([]byte("hello")) + }, + fnv64aSum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Fnv64a{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func fnv64aSum(b []byte) []byte { + h := fnv.New64a() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestFnv64a_String(t *testing.T) { + assert.Equals(t, (&Fnv64a{}).String(), "fnv64a") +} diff --git a/checksum/fnv.go b/checksum/fnv.go new file mode 100644 index 0000000..dc6f82c --- /dev/null +++ b/checksum/fnv.go @@ -0,0 +1,147 @@ +package checksum + +import ( + "hash" + "hash/fnv" +) + +type ( + Fnv32 struct { + d hash.Hash + } + Fnv32a struct { + d hash.Hash + } + Fnv64 struct { + d hash.Hash + } + Fnv64a struct { + d hash.Hash + } + Fnv128 struct { + d hash.Hash + } + Fnv128a struct { + d hash.Hash + } +) + +func (m *Fnv32) String() string { + return "fnv32" +} + +func (m *Fnv32) Append(data []byte) { + if m.d == nil { + m.d = fnv.New32() + } + + m.d.Write(data) +} + +func (m *Fnv32) Finish() []byte { + if m.d == nil { + m.d = fnv.New32() + } + + return m.d.Sum(nil) +} + +func (m *Fnv32a) String() string { + return "fnv32a" +} + +func (m *Fnv32a) Append(data []byte) { + if m.d == nil { + m.d = fnv.New32a() + } + + m.d.Write(data) +} + +func (m *Fnv32a) Finish() []byte { + if m.d == nil { + m.d = fnv.New32a() + } + + return m.d.Sum(nil) +} + +func (m *Fnv64) String() string { + return "fnv64" +} + +func (m *Fnv64) Append(data []byte) { + if m.d == nil { + m.d = fnv.New64() + } + + m.d.Write(data) +} + +func (m *Fnv64) Finish() []byte { + if m.d == nil { + m.d = fnv.New64() + } + + return m.d.Sum(nil) +} + +func (m *Fnv64a) String() string { + return "fnv64a" +} + +func (m *Fnv64a) Append(data []byte) { + if m.d == nil { + m.d = fnv.New64a() + } + + m.d.Write(data) +} + +func (m *Fnv64a) Finish() []byte { + if m.d == nil { + m.d = fnv.New64a() + } + + return m.d.Sum(nil) +} + +func (m *Fnv128) String() string { + return "fnv128" +} + +func (m *Fnv128) Append(data []byte) { + if m.d == nil { + m.d = fnv.New128() + } + + m.d.Write(data) +} + +func (m *Fnv128) Finish() []byte { + if m.d == nil { + m.d = fnv.New128() + } + + return m.d.Sum(nil) +} + +func (m *Fnv128a) String() string { + return "fnv128a" +} + +func (m *Fnv128a) Append(data []byte) { + if m.d == nil { + m.d = fnv.New128a() + } + + m.d.Write(data) +} + +func (m *Fnv128a) Finish() []byte { + if m.d == nil { + m.d = fnv.New128a() + } + + return m.d.Sum(nil) +} diff --git a/checksum/md5.go b/checksum/md5.go new file mode 100644 index 0000000..ddfd8f7 --- /dev/null +++ b/checksum/md5.go @@ -0,0 +1,32 @@ +package checksum + +import ( + "crypto/md5" + "hash" +) + +type ( + Md5 struct { + d hash.Hash + } +) + +func (m *Md5) String() string { + return "md5" +} + +func (m *Md5) Append(data []byte) { + if m.d == nil { + m.d = md5.New() + } + + m.d.Write(data) +} + +func (m *Md5) Finish() []byte { + if m.d == nil { + m.d = md5.New() + } + + return m.d.Sum(nil) +} diff --git a/checksum/md5_test.go b/checksum/md5_test.go new file mode 100644 index 0000000..c834b61 --- /dev/null +++ b/checksum/md5_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "crypto/md5" + "github.com/tursom/checksum/assert" + "hash" + "testing" +) + +func TestMd5_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Md5) + want []byte + }{ + { + "nil", + fields{}, + nil, + md5.New().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Md5) { + m.Append([]byte("hello")) + }, + md5sum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Md5{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func md5sum(b []byte) []byte { + h := md5.New() + h.Write(b) + return h.Sum(nil) +} + +func TestMd5_String(t *testing.T) { + assert.Equals(t, (&Md5{}).String(), "md5") +} diff --git a/checksum/murmur3.go b/checksum/murmur3.go new file mode 100644 index 0000000..3f3ba38 --- /dev/null +++ b/checksum/murmur3.go @@ -0,0 +1,80 @@ +package checksum + +import ( + "github.com/spaolacci/murmur3" + "hash" + + _ "github.com/spaolacci/murmur3" +) + +type ( + Murmur332 struct { + d hash.Hash + } + Murmur364 struct { + d hash.Hash + } + Murmur3128 struct { + d hash.Hash + } +) + +func (s *Murmur332) String() string { + return "murmur3 32" +} + +func (s *Murmur332) Append(data []byte) { + if s.d == nil { + s.d = murmur3.New32() + } + + s.d.Write(data) +} + +func (s *Murmur332) Finish() []byte { + if s.d == nil { + s.d = murmur3.New32() + } + + return s.d.Sum(nil) +} + +func (s *Murmur364) String() string { + return "murmur3 64" +} + +func (s *Murmur364) Append(data []byte) { + if s.d == nil { + s.d = murmur3.New64() + } + + s.d.Write(data) +} + +func (s *Murmur364) Finish() []byte { + if s.d == nil { + s.d = murmur3.New64() + } + + return s.d.Sum(nil) +} + +func (s *Murmur3128) String() string { + return "murmur3 128" +} + +func (s *Murmur3128) Append(data []byte) { + if s.d == nil { + s.d = murmur3.New128() + } + + s.d.Write(data) +} + +func (s *Murmur3128) Finish() []byte { + if s.d == nil { + s.d = murmur3.New128() + } + + return s.d.Sum(nil) +} diff --git a/checksum/murmur3_128_test.go b/checksum/murmur3_128_test.go new file mode 100644 index 0000000..e7fca34 --- /dev/null +++ b/checksum/murmur3_128_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/spaolacci/murmur3" + "github.com/tursom/checksum/assert" + "hash" + "testing" +) + +func TestMurmur3128_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Murmur3128) + want []byte + }{ + { + "nil", + fields{}, + nil, + murmur3.New128().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Murmur3128) { + m.Append([]byte("hello")) + }, + murmur3128Sum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Murmur3128{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func murmur3128Sum(b []byte) []byte { + h := murmur3.New128() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestMurmur3128_String(t *testing.T) { + assert.Equals(t, (&Murmur3128{}).String(), "murmur3 128") +} diff --git a/checksum/murmur3_32_test.go b/checksum/murmur3_32_test.go new file mode 100644 index 0000000..95c42ef --- /dev/null +++ b/checksum/murmur3_32_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/spaolacci/murmur3" + "github.com/tursom/checksum/assert" + "hash" + "testing" +) + +func TestMurmur332_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Murmur332) + want []byte + }{ + { + "nil", + fields{}, + nil, + murmur3.New32().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Murmur332) { + m.Append([]byte("hello")) + }, + murmur332Sum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Murmur332{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func murmur332Sum(b []byte) []byte { + h := murmur3.New32() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestMurmur332_String(t *testing.T) { + assert.Equals(t, (&Murmur332{}).String(), "murmur3 32") +} diff --git a/checksum/murmur3_64_test.go b/checksum/murmur3_64_test.go new file mode 100644 index 0000000..2f235b1 --- /dev/null +++ b/checksum/murmur3_64_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "github.com/spaolacci/murmur3" + "github.com/tursom/checksum/assert" + "hash" + "testing" +) + +func TestMurmur364_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Murmur364) + want []byte + }{ + { + "nil", + fields{}, + nil, + murmur3.New64().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Murmur364) { + m.Append([]byte("hello")) + }, + murmur364Sum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Murmur364{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func murmur364Sum(b []byte) []byte { + h := murmur3.New64() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestMurmur364_String(t *testing.T) { + assert.Equals(t, (&Murmur364{}).String(), "murmur3 64") +} diff --git a/checksum/sha1.go b/checksum/sha1.go new file mode 100644 index 0000000..2ac8cbb --- /dev/null +++ b/checksum/sha1.go @@ -0,0 +1,32 @@ +package checksum + +import ( + "crypto/sha1" + "hash" +) + +type ( + Sha1 struct { + d hash.Hash + } +) + +func (s *Sha1) String() string { + return "sha1" +} + +func (s *Sha1) Append(data []byte) { + if s.d == nil { + s.d = sha1.New() + } + + s.d.Write(data) +} + +func (s *Sha1) Finish() []byte { + if s.d == nil { + s.d = sha1.New() + } + + return s.d.Sum(nil) +} diff --git a/checksum/sha1_test.go b/checksum/sha1_test.go new file mode 100644 index 0000000..62fe9b3 --- /dev/null +++ b/checksum/sha1_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "crypto/sha1" + "github.com/tursom/checksum/assert" + "hash" + "testing" +) + +func TestSha1_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Sha1) + want []byte + }{ + { + "nil", + fields{}, + nil, + sha1.New().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Sha1) { + m.Append([]byte("hello")) + }, + sha1Sum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Sha1{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func sha1Sum(b []byte) []byte { + h := sha1.New() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestSha1_String(t *testing.T) { + assert.Equals(t, (&Sha1{}).String(), "sha1") +} diff --git a/checksum/sha256.go b/checksum/sha256.go new file mode 100644 index 0000000..25cf267 --- /dev/null +++ b/checksum/sha256.go @@ -0,0 +1,32 @@ +package checksum + +import ( + "crypto/sha256" + "hash" +) + +type ( + Sha256 struct { + d hash.Hash + } +) + +func (s *Sha256) String() string { + return "sha256" +} + +func (s *Sha256) Append(data []byte) { + if s.d == nil { + s.d = sha256.New() + } + + s.d.Write(data) +} + +func (s *Sha256) Finish() []byte { + if s.d == nil { + s.d = sha256.New() + } + + return s.d.Sum(nil) +} diff --git a/checksum/sha256_test.go b/checksum/sha256_test.go new file mode 100644 index 0000000..c9d1d39 --- /dev/null +++ b/checksum/sha256_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "crypto/sha256" + "github.com/tursom/checksum/assert" + "hash" + "testing" +) + +func TestSha256_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Sha256) + want []byte + }{ + { + "nil", + fields{}, + nil, + sha256.New().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Sha256) { + m.Append([]byte("hello")) + }, + sha256Sum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Sha256{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func sha256Sum(b []byte) []byte { + h := sha256.New() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestSha256_String(t *testing.T) { + assert.Equals(t, (&Sha256{}).String(), "sha256") +} diff --git a/checksum/sha512.go b/checksum/sha512.go new file mode 100644 index 0000000..4db8c5b --- /dev/null +++ b/checksum/sha512.go @@ -0,0 +1,32 @@ +package checksum + +import ( + "crypto/sha512" + "hash" +) + +type ( + Sha512 struct { + d hash.Hash + } +) + +func (s *Sha512) String() string { + return "sha512" +} + +func (s *Sha512) Append(data []byte) { + if s.d == nil { + s.d = sha512.New() + } + + s.d.Write(data) +} + +func (s *Sha512) Finish() []byte { + if s.d == nil { + s.d = sha512.New() + } + + return s.d.Sum(nil) +} diff --git a/checksum/sha512_test.go b/checksum/sha512_test.go new file mode 100644 index 0000000..387ac07 --- /dev/null +++ b/checksum/sha512_test.go @@ -0,0 +1,57 @@ +package checksum + +import ( + "crypto/sha512" + "github.com/tursom/checksum/assert" + "hash" + "testing" +) + +func TestSha512_Finish(t *testing.T) { + type fields struct { + d hash.Hash + } + tests := []struct { + name string + fields fields + builder func(m *Sha512) + want []byte + }{ + { + "nil", + fields{}, + nil, + sha512.New().Sum(nil), + }, + { + "hello", + fields{}, + func(m *Sha512) { + m.Append([]byte("hello")) + }, + sha512Sum([]byte("hello")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Sha512{ + d: tt.fields.d, + } + if tt.builder != nil { + tt.builder(m) + } + + assert.Equals(t, m.Finish(), tt.want) + }) + } +} + +func sha512Sum(b []byte) []byte { + h := sha512.New() + _, _ = h.Write(b) + return h.Sum(nil) +} + +func TestSha512_String(t *testing.T) { + assert.Equals(t, (&Sha512{}).String(), "sha512") +} diff --git a/cmd/checksum/main.go b/cmd/checksum/main.go new file mode 100644 index 0000000..3591e6d --- /dev/null +++ b/cmd/checksum/main.go @@ -0,0 +1,109 @@ +package main + +import ( + "errors" + "fmt" + "github.com/tursom/checksum/checksum" + "io" + "io/fs" + "os" + "path/filepath" +) + +var ( + hashFuncs = []func() checksum.Func{ + func() checksum.Func { return &checksum.Md5{} }, + func() checksum.Func { return &checksum.Sha1{} }, + func() checksum.Func { return &checksum.Sha256{} }, + func() checksum.Func { return &checksum.Sha512{} }, + func() checksum.Func { return &checksum.Murmur332{} }, + func() checksum.Func { return &checksum.Murmur364{} }, + func() checksum.Func { return &checksum.Murmur3128{} }, + func() checksum.Func { return &checksum.Adler32{} }, + func() checksum.Func { return &checksum.Crc32Ieee{} }, + func() checksum.Func { return &checksum.Crc32Castagnoli{} }, + func() checksum.Func { return &checksum.Crc32Koopman{} }, + func() checksum.Func { return &checksum.Crc64Iso{} }, + func() checksum.Func { return &checksum.Crc64Ecma{} }, + func() checksum.Func { return &checksum.Fnv32{} }, + func() checksum.Func { return &checksum.Fnv32a{} }, + func() checksum.Func { return &checksum.Fnv64{} }, + func() checksum.Func { return &checksum.Fnv64a{} }, + func() checksum.Func { return &checksum.Fnv128{} }, + func() checksum.Func { return &checksum.Fnv128a{} }, + } +) + +func main() { + path, checksumType := readConfig() + doCheck(path, hashFuncs[checksumType-1]) + waitExit() +} + +func readConfig() (string, uint) { + fmt.Println("Please select checksum path:") + fmt.Print(">>> ") + var path string + if _, err := fmt.Scanln(&path); err != nil { + panic(err) + } + + fmt.Println("Please select checksum type:") + for i, f := range hashFuncs { + fmt.Printf("%d. %s\n", i+1, f().String()) + } + fmt.Print(">>> ") + var checksumType uint + if _, err := fmt.Scanln(&checksumType); err != nil { + panic(err) + } + return path, checksumType +} + +func doCheck(path string, factory func() checksum.Func) { + checkFile(path, factory) +} + +func checkFile(path string, factory func() checksum.Func) { + file, err := os.Open(path) + if err != nil { + panic(err) + } + defer file.Close() + + fileStat, err := file.Stat() + if err != nil { + panic(errors.New(fmt.Sprintf("failed to check status: %s", err))) + } + + switch mode := fileStat.Mode(); { + case mode.IsDir(): + filepath.Walk(file.Name(), func(subPath string, info fs.FileInfo, err error) error { + if subPath == path { + return nil + } + checkFile(subPath, factory) + return nil + }) + case mode.IsRegular(): + f := factory() + + buffer := make([]byte, 1024) + for { + n, err := file.Read(buffer) + if n == 0 || err == io.EOF { + break + } else if err != nil { + panic(err) + } + f.Append(buffer[0:n]) + } + + fmt.Printf("file: %s\nchecksum: %x\n\n", path, f.Finish()) + } +} + +func waitExit() { + fmt.Println("Press enter to exit.") + _, _ = fmt.Scanln() +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..59950a7 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/tursom/checksum + +go 1.20 + +require github.com/spaolacci/murmur3 v1.1.0