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:
Wu Tingfeng 2023-05-03 22:52:14 +08:00 committed by GitHub
parent 464cef2de9
commit d68e89bd8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 94 additions and 26 deletions

View File

@ -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

View File

@ -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
View File

@ -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
View File

@ -1,3 +1,5 @@
module github.com/corona10/goimagehash
go 1.11
require github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646

View File

@ -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) {

View File

@ -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)

View File

@ -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,28 +106,50 @@ func TestSerialization(t *testing.T) {
}
// test for ExtIExtImageHash
sizeList := []int{8, 16}
for _, size := range sizeList {
hash, err := ExtPerceptionHash(img, size, size)
checkErr(err)
for _, extMethod := range extMethods {
extMethodStr := runtime.FuncForPC(reflect.ValueOf(extMethod).Pointer()).Name()
sizeList := []int{8, 16}
for _, size := range sizeList {
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)
}
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, extMethodStr, ex)
}
reHash, err := ExtImageHashFromString(hex)
checkErr(err)
reHash, err := ExtImageHashFromString(hex)
checkErr(err)
distance, err := hash.Distance(reHash)
checkErr(err)
distance, err := hash.Distance(reHash)
checkErr(err)
if distance != 0 {
t.Errorf("Original and unserialized objects should be identical, got distance=%v; %v of '%v'", distance, "ExtPerceptionHash", ex)
if distance != 0 {
t.Errorf("Original and unserialized objects should be identical, got distance=%v; %v of '%v'", distance, "ExtPerceptionHash", ex)
}
}
}
}
// 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")
}
}

View File

@ -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) {

View File

@ -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++ {