Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
coverage.out
/vendor/

12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,15 @@ coveralls-deps:
@echo "Installing coveralls"
@go get github.com/mattn/goveralls
@go install github.com/mattn/goveralls

.PHONY: lint-deps
lint-deps:
@echo "Installing lint deps"
@go install github.com/golangci/golangci-lint/v2/cmd/[email protected]

.PHONY: lint
lint: lint-deps
@echo "Running go-linter"
@go mod tidy
@go mod vendor
@golangci-lint run --config=./.golangci.yml --modules-download-mode vendor --verbose
80 changes: 80 additions & 0 deletions hasher/hasher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Package hasher provides types and interfaces for hash calculating.
package hasher

import (
"crypto/sha1" //nolint:gosec
"crypto/sha256"
"errors"
"fmt"
"hash"
)

// ErrDataIsNil is returned if the passed data is nil.
var ErrDataIsNil = errors.New("data is nil")

// Hasher is the interface that storage hashers must implement.
// It provides low-level operations for hash calculating.
type Hasher interface {
Name() string
Hash(data []byte) ([]byte, error)
}

type sha256Hasher struct {
hash hash.Hash
}

// NewSHA256Hasher creates a new sha256Hasher instance.
func NewSHA256Hasher() Hasher {
return &sha256Hasher{
hash: sha256.New(),
}
}

// Name implements Hasher interface.
func (h *sha256Hasher) Name() string {
return "sha256"
}

// Hash implements Hasher interface.
func (h *sha256Hasher) Hash(data []byte) ([]byte, error) {
if data == nil {
return nil, ErrDataIsNil
}

n, err := h.hash.Write(data)
if n < len(data) || err != nil {
return nil, fmt.Errorf("failed to write data: %w", err)
}

return h.hash.Sum(nil), nil
}

type sha1Hasher struct {
hash hash.Hash
}

// NewSHA1Hasher creates a new NewSHA1Hasher instance.
func NewSHA1Hasher() Hasher {
return &sha1Hasher{
hash: sha1.New(), //nolint:gosec
}
}

// Name implements Hasher interface.
func (h *sha1Hasher) Name() string {
return "sha1"
}

// Hash implements Hasher interface.
func (h *sha1Hasher) Hash(data []byte) ([]byte, error) {
if data == nil {
return nil, ErrDataIsNil
}

n, err := h.hash.Write(data)
if n < len(data) || err != nil {
return nil, fmt.Errorf("failed to write data: %w", err)
}

return h.hash.Sum(nil), nil
}
107 changes: 107 additions & 0 deletions hasher/hasher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package hasher_test

import (
"encoding/hex"
"testing"

"github.com/stretchr/testify/assert"
"github.com/tarantool/go-storage/hasher"
)

func TestSHA1Hasher(t *testing.T) {
t.Parallel()

tests := []struct {
name string
in []byte
out string
}{
{"empty", []byte(""), "da39a3ee5e6b4b0d3255bfef95601890afd80709"},
{"abc", []byte("abc"), "a9993e364706816aba3e25717850c26c9cd0d89d"},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()

h := hasher.NewSHA1Hasher()

result, _ := h.Hash(test.in)

assert.Equal(t, test.out, hex.EncodeToString(result))
})
}
}

func TestSHA1Hasher_negative(t *testing.T) {
t.Parallel()

tests := []struct {
name string
in []byte
expectedErrorText string
}{
{"nil", nil, "data is nil"},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()

h := hasher.NewSHA1Hasher()

_, err := h.Hash(test.in)

assert.Contains(t, err.Error(), test.expectedErrorText)
})
}
}

func TestSHA256Hasher(t *testing.T) {
t.Parallel()

tests := []struct {
name string
in []byte
out string
}{
{"empty", []byte(""), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
{"abc", []byte("abc"), "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()

h := hasher.NewSHA256Hasher()

result, _ := h.Hash(test.in)

assert.Equal(t, test.out, hex.EncodeToString(result))
})
}
}

func TestSHA256Hasher_negative(t *testing.T) {
t.Parallel()

tests := []struct {
name string
in []byte
expectedErrorText string
}{
{"nil", nil, "data is nil"},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()

h := hasher.NewSHA256Hasher()

_, err := h.Hash(test.in)

assert.Contains(t, err.Error(), test.expectedErrorText)
})
}
}
Loading