Increase test coverage to 96.6% (#61)
* gitignore *.html for test coverage reports * fix typos * Increase hashcompute.go test coverage to 100 percent * Add new Go versions. Upgrade GitHub Actions. * Add tests for missing ext hashes * Add test for hashing non-hexadecimal string * Add tests for loading empty bytes buffer * Run go fmt * Fix comments * Fix comments * Fix spelling * fix actions versions * Upgrade to actions/setup-go@v4 * Add minimum Go version for go.mod
This commit is contained in:
parent
464cef2de9
commit
d68e89bd8f
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -4,12 +4,12 @@ jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.6.x, 1.7.x, 1.8.x, 1.9.x, 1.10.x, 1.11.x, 1.12.x, 1.13.x, 1.14.x, 1.15.x, 1.16.x, 1.17.x, 1.18.x]
|
||||
go-version: [1.6.x, 1.7.x, 1.8.x, 1.9.x, 1.10.x, 1.11.x, 1.12.x, 1.13.x, 1.14.x, 1.15.x, 1.16.x, 1.17.x, 1.18.x, 1.19.x, 1.20.x]
|
||||
platform: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v1
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Set GOPATH
|
||||
|
4
.github/workflows/ci_gomodule.yml
vendored
4
.github/workflows/ci_gomodule.yml
vendored
@ -4,12 +4,12 @@ jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.11.x, 1.12.x, 1.13.x, 1.14.x, 1.15.x, 1.16.x, 1.17.x, 1.18.x]
|
||||
go-version: [1.11.x, 1.12.x, 1.13.x, 1.14.x, 1.15.x, 1.16.x, 1.17.x, 1.18.x, 1.19.x, 1.20.x]
|
||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v1
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Checkout code
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
*.html
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
|
2
go.mod
2
go.mod
@ -1,3 +1,5 @@
|
||||
module github.com/corona10/goimagehash
|
||||
|
||||
go 1.11
|
||||
|
||||
require github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
"github.com/nfnt/resize"
|
||||
)
|
||||
|
||||
// AverageHash fuction returns a hash computation of average hash.
|
||||
// AverageHash function returns a hash computation of average hash.
|
||||
// Implementation follows
|
||||
// http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html
|
||||
func AverageHash(img image.Image) (*ImageHash, error) {
|
||||
|
@ -124,6 +124,34 @@ func TestNilHashCompute(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtendHashCompute(t *testing.T) {
|
||||
file, err := os.Open("_examples/sample1.jpg")
|
||||
if err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
defer file.Close()
|
||||
img, err := jpeg.Decode(file)
|
||||
if err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
|
||||
hash, err := ExtPerceptionHash(img, 0, 8)
|
||||
if err == nil {
|
||||
t.Errorf("Error should be got.")
|
||||
}
|
||||
if hash != nil {
|
||||
t.Errorf("Nil hash should be got. but got %v", hash)
|
||||
}
|
||||
|
||||
hash, err = ExtPerceptionHash(img, 16, 2)
|
||||
if err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if hash == nil {
|
||||
t.Errorf("Hash should be got.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilExtendHashCompute(t *testing.T) {
|
||||
hash, err := ExtAverageHash(nil, 8, 8)
|
||||
if err == nil {
|
||||
@ -348,7 +376,7 @@ func BenchmarkAverageHash(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDiffrenceHash(b *testing.B) {
|
||||
func BenchmarkDifferenceHash(b *testing.B) {
|
||||
file1, err := os.Open("_examples/sample3.jpg")
|
||||
if err != nil {
|
||||
b.Errorf("%s", err)
|
||||
|
@ -66,6 +66,9 @@ func TestSerialization(t *testing.T) {
|
||||
methods := []func(img image.Image) (*ImageHash, error){
|
||||
AverageHash, PerceptionHash, DifferenceHash,
|
||||
}
|
||||
extMethods := []func(img image.Image, width int, height int) (*ExtImageHash, error){
|
||||
ExtAverageHash, ExtPerceptionHash, ExtDifferenceHash,
|
||||
}
|
||||
examples := []string{
|
||||
"_examples/sample1.jpg", "_examples/sample2.jpg", "_examples/sample3.jpg", "_examples/sample4.jpg",
|
||||
}
|
||||
@ -103,15 +106,17 @@ func TestSerialization(t *testing.T) {
|
||||
}
|
||||
|
||||
// test for ExtIExtImageHash
|
||||
for _, extMethod := range extMethods {
|
||||
extMethodStr := runtime.FuncForPC(reflect.ValueOf(extMethod).Pointer()).Name()
|
||||
sizeList := []int{8, 16}
|
||||
for _, size := range sizeList {
|
||||
hash, err := ExtPerceptionHash(img, size, size)
|
||||
hash, err := extMethod(img, size, size)
|
||||
checkErr(err)
|
||||
|
||||
hex := hash.ToString()
|
||||
// len(kind) == 1, len(":") == 1
|
||||
if len(hex) != size*size/4+2 {
|
||||
t.Errorf("Got invalid hex string '%v'; %v of '%v'", hex, "ExtPerceptionHash", ex)
|
||||
t.Errorf("Got invalid hex string '%v'; %v of '%v'", hex, extMethodStr, ex)
|
||||
}
|
||||
|
||||
reHash, err := ExtImageHashFromString(hex)
|
||||
@ -125,6 +130,26 @@ func TestSerialization(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test for hashing empty string
|
||||
imageHash, err := ImageHashFromString("")
|
||||
if imageHash != nil {
|
||||
t.Errorf("Expected reHash to be nil, got %v", imageHash)
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("Should got error for empty string")
|
||||
}
|
||||
extImageHash, err := ExtImageHashFromString("")
|
||||
if extImageHash != nil {
|
||||
t.Errorf("Expected reHash to be nil, got %v", extImageHash)
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("Should got error for empty string")
|
||||
}
|
||||
|
||||
// test for hashing invalid (non-hexadecimal) string
|
||||
extImageHash, err = ExtImageHashFromString("k:g")
|
||||
}
|
||||
|
||||
func TestDifferentBitSizeHash(t *testing.T) {
|
||||
@ -231,4 +256,16 @@ func TestDumpAndLoad(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test for loading empty bytes buffer
|
||||
var b bytes.Buffer
|
||||
bar := bufio.NewReader(&b)
|
||||
_, err := LoadImageHash(bar)
|
||||
if err == nil {
|
||||
t.Errorf("Should got error for empty bytes buffer")
|
||||
}
|
||||
_, err = LoadExtImageHash(bar)
|
||||
if err == nil {
|
||||
t.Errorf("Should got error for empty bytes buffer")
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ func forwardTransform(input, temp []float64, Len int) {
|
||||
input[Len-2], input[Len-1] = temp[halfLen-1], temp[Len-1]
|
||||
}
|
||||
|
||||
// DCT2D function returns a result of DCT2D by using the seperable property.
|
||||
// DCT2D function returns a result of DCT2D by using the separable property.
|
||||
func DCT2D(input [][]float64, w int, h int) [][]float64 {
|
||||
output := make([][]float64, h)
|
||||
for i := range output {
|
||||
@ -74,7 +74,7 @@ func DCT2D(input [][]float64, w int, h int) [][]float64 {
|
||||
return output
|
||||
}
|
||||
|
||||
// DCT2DFast64 function returns a result of DCT2D by using the seperable property.
|
||||
// DCT2DFast64 function returns a result of DCT2D by using the separable property.
|
||||
// Fast uses static DCT tables for improved performance. Returns flattened pixels.
|
||||
func DCT2DFast64(input *[]float64) (flattens [64]float64) {
|
||||
if len(*input) != 64*64 {
|
||||
@ -98,7 +98,7 @@ func DCT2DFast64(input *[]float64) (flattens [64]float64) {
|
||||
return
|
||||
}
|
||||
|
||||
// DCT2DFast256 function returns a result of DCT2D by using the seperable property.
|
||||
// DCT2DFast256 function returns a result of DCT2D by using the separable property.
|
||||
// DCT type II, unscaled. Algorithm by Byeong Gi Lee, 1984.
|
||||
// Fast uses static DCT tables for improved performance. Returns flattened pixels.
|
||||
func DCT2DFast256(input *[]float64) (flattens [256]float64) {
|
||||
|
@ -58,7 +58,7 @@ func rgb2GrayDefault(colorImg image.Image, pixels []float64, s int) {
|
||||
}
|
||||
}
|
||||
|
||||
// rgb2GrayYCbCR uses *image.YCbCr which is signifiantly faster than the image.Image interface.
|
||||
// rgb2GrayYCbCR uses *image.YCbCr which is significantly faster than the image.Image interface.
|
||||
func rgb2GrayYCbCR(colorImg *image.YCbCr, pixels []float64, s int) {
|
||||
for i := 0; i < s; i++ {
|
||||
for j := 0; j < s; j++ {
|
||||
@ -67,7 +67,7 @@ func rgb2GrayYCbCR(colorImg *image.YCbCr, pixels []float64, s int) {
|
||||
}
|
||||
}
|
||||
|
||||
// rgb2GrayYCbCR uses *image.RGBA which is signifiantly faster than the image.Image interface.
|
||||
// rgb2GrayRGBA uses *image.RGBA which is significantly faster than the image.Image interface.
|
||||
func rgb2GrayRGBA(colorImg *image.RGBA, pixels []float64, s int) {
|
||||
for i := 0; i < s; i++ {
|
||||
for j := 0; j < s; j++ {
|
||||
|
Loading…
Reference in New Issue
Block a user