...

Source file src/gonum.org/v1/plot/cmpimg/cmpimg_test.go

Documentation: gonum.org/v1/plot/cmpimg

     1  // Copyright ©2017 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package cmpimg
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/base64"
    10  	"fmt"
    11  	"image"
    12  	"image/draw"
    13  	"image/png"
    14  	"os"
    15  	"path/filepath"
    16  	"strings"
    17  	"testing"
    18  )
    19  
    20  const wantDiffEncoded = `iVBORw0KGgoAAAANSUhEUgAAAZAAAAEzEAIAAADAxR6YAAAHBklEQVR4nOzYjW3kRABA4RWiC0QXUMami2xRSRfrMu76gDKQZQ3+2907xEMg8X3SXZKxdzwZ29JTfrgAAJASWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAsR//7QX8X12v8//T9E/NvPje+R+tZjvP9882PjV/naZvf+J8lb96xb+/l+uar9d5zfPX8+rnY/PocvTZ9ebj4+j5TmyPjauNM8f8YyXrGh7NM2ZaPjXmHj8dZx4j+zUsax2zr0fHjGOG9frrOfs9WM/bjmx3bnxmP368/2MHzmtfj61j49/2+tv1bO/Ho1UdzzyO7898NsNx/NU+bHfkeMXZzz+Nnz4/3m/rPXi/He/B6r55Tt+evk3btZ73ffsGfH6MPfn8+PL1cvnydVnB779dLrfb/c/fa+zT9imaXhw9P3fH53H9fbdvwH6/lvdv/zSvT/B4e/dzL2e/7d7bZ98vOzqPvG3mWPZ42d375g1f5tzfgePI8Uk8P3GP1nAc+fWXeWT+f5rmOzH2dn5K9nt0/+b8j97ddYXnt+31vq2zHD+/3onz0XGH3m/P3tBnb8szr2Z5vdOvZzyv6Di+fDdNt9t5Dn/BAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgAAAOC/zV+wAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAICawAABiAgsAIPZHAAAA///KAlB2mCuyaAAAAABJRU5ErkJggg==`
    21  
    22  func TestDiff(t *testing.T) {
    23  	got, err := os.ReadFile(filepath.FromSlash("./testdata/failed_input.png"))
    24  	if err != nil {
    25  		t.Fatalf("failed to read failed file: %v", err)
    26  	}
    27  	want, err := os.ReadFile(filepath.FromSlash("./testdata/good_golden.png"))
    28  	if err != nil {
    29  		t.Fatalf("failed to read golden file: %v", err)
    30  	}
    31  
    32  	v1, _, err := image.Decode(bytes.NewReader(got))
    33  	if err != nil {
    34  		t.Fatalf("unexpected error decoding failed file: %v", err)
    35  	}
    36  	v2, _, err := image.Decode(bytes.NewReader(want))
    37  	if err != nil {
    38  		t.Fatalf("unexpected error decoding golden file: %v", err)
    39  	}
    40  
    41  	dst := image.NewRGBA64(v1.Bounds().Union(v2.Bounds()))
    42  	rect := Diff(dst, v1, v2)
    43  	if rect != dst.Bounds() {
    44  		t.Errorf("unexpected bound for diff: got:%+v want:%+v", rect, dst.Bounds())
    45  	}
    46  
    47  	var buf bytes.Buffer
    48  	err = png.Encode(&buf, dst)
    49  	if err != nil {
    50  		t.Fatalf("failed to encode difference png: %v", err)
    51  	}
    52  	gotDiff := base64.StdEncoding.EncodeToString(buf.Bytes())
    53  	if gotDiff != wantDiffEncoded {
    54  		t.Errorf("unexpected encoded diff value:\ngot:%s\nwant:%s", gotDiff, wantDiffEncoded)
    55  	}
    56  }
    57  
    58  func TestEqual(t *testing.T) {
    59  	got, err := os.ReadFile("testdata/approx_got_golden.png")
    60  	if err != nil {
    61  		t.Fatal(err)
    62  	}
    63  
    64  	ok, err := Equal("png", got, got)
    65  	if err != nil {
    66  		t.Fatalf("could not compare images: %+v", err)
    67  	}
    68  	if !ok {
    69  		t.Fatalf("same image does not compare equal")
    70  	}
    71  }
    72  
    73  func TestEqualApproxPNG(t *testing.T) {
    74  	got, err := os.ReadFile("testdata/approx_got_golden.png")
    75  	if err != nil {
    76  		t.Fatal(err)
    77  	}
    78  
    79  	want, err := os.ReadFile("testdata/approx_want_golden.png")
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  
    84  	for _, tc := range []struct {
    85  		delta float64
    86  		ok    bool
    87  	}{
    88  		{0, false},
    89  		{0.01, false},
    90  		{0.02, false},
    91  		{0.05, true},
    92  		{0.1, true},
    93  		{1, true},
    94  	} {
    95  		t.Run(fmt.Sprintf("delta=%g", tc.delta), func(t *testing.T) {
    96  			ok, err := EqualApprox("png", got, want, tc.delta)
    97  			if err != nil {
    98  				t.Fatalf("could not compare images: %+v", err)
    99  			}
   100  			if ok != tc.ok {
   101  				t.Fatalf("got=%v, want=%v", ok, tc.ok)
   102  			}
   103  		})
   104  	}
   105  }
   106  
   107  func TestEqualApprox(t *testing.T) {
   108  	read := func(name string) []byte {
   109  		raw, err := os.ReadFile(name)
   110  		if err != nil {
   111  			t.Fatalf("could not read file %q: %+v", name, err)
   112  		}
   113  		return raw
   114  	}
   115  
   116  	asPNG_RGBA64 := func(raw []byte) []byte {
   117  		src, _, err := image.Decode(bytes.NewReader(raw))
   118  		if err != nil {
   119  			t.Fatalf("could not decode image: %+v", err)
   120  		}
   121  		var (
   122  			bnds = src.Bounds()
   123  			dst  = image.NewRGBA64(bnds)
   124  			out  = new(bytes.Buffer)
   125  		)
   126  		draw.Draw(dst, bnds, src, image.Point{}, draw.Src)
   127  		err = png.Encode(out, dst)
   128  		if err != nil {
   129  			t.Fatalf("could not encode image: %+v", err)
   130  		}
   131  		return out.Bytes()
   132  	}
   133  
   134  	for _, tc := range []struct {
   135  		name  string
   136  		img1  []byte
   137  		img2  []byte
   138  		delta float64
   139  		want  bool
   140  	}{
   141  		{
   142  			name: "svg-ok",
   143  			img1: []byte("<svg></svg>"),
   144  			img2: []byte("<svg></svg>"),
   145  			want: true,
   146  		},
   147  		{
   148  			name: "svg-diff",
   149  			img1: []byte("<svg></svg>"),
   150  			img2: []byte("<svg>1</svg>"),
   151  			want: false,
   152  		},
   153  		{
   154  			name: "eps-ok",
   155  			img1: []byte("line1\nline2\nCreationDate:now\n"),
   156  			img2: []byte("line1\nline2\nCreationDate:later\n"),
   157  			want: true,
   158  		},
   159  		{
   160  			name: "eps-diff-1",
   161  			img1: []byte("line1\nline2\nCreationDate:now\n"),
   162  			img2: []byte("line1\nline2\nCreationDate:later"),
   163  			want: false,
   164  		},
   165  		{
   166  			name: "eps-diff-2",
   167  			img1: []byte("line1\nline2\nCreationDate:now\n"),
   168  			img2: []byte("line1\nline3\nCreationDate:later\n"),
   169  			want: false,
   170  		},
   171  		{
   172  			name: "pdf-ok",
   173  			img1: read("../vg/vgpdf/testdata/arc_golden.pdf"),
   174  			img2: read("../vg/vgpdf/testdata/arc_golden.pdf"),
   175  			want: true,
   176  		},
   177  		{
   178  			name: "pdf-diff",
   179  			img1: read("../vg/vgpdf/testdata/arc_golden.pdf"),
   180  			img2: read("../vg/vgpdf/testdata/issue540_golden.pdf"),
   181  			want: false,
   182  		},
   183  		{
   184  			name: "pdf-diff-2",
   185  			img1: read("../vg/vgpdf/testdata/arc_golden.pdf"),
   186  			img2: read("../vg/vgpdf/testdata/multipage_golden.pdf"),
   187  			want: false,
   188  		},
   189  		{
   190  			name:  "png-ok",
   191  			img1:  read("testdata/approx_got_golden.png"),
   192  			img2:  read("testdata/approx_want_golden.png"),
   193  			delta: 0.1,
   194  			want:  true,
   195  		},
   196  		{
   197  			name:  "png-ok-rgba64",
   198  			img1:  read("testdata/approx_got_golden.png"),
   199  			img2:  asPNG_RGBA64(read("testdata/approx_want_golden.png")),
   200  			delta: 0.1,
   201  			want:  true,
   202  		},
   203  		{
   204  			name:  "png-ok-rgba64-2",
   205  			img1:  read("testdata/approx_got_golden.png"),
   206  			img2:  asPNG_RGBA64(read("testdata/approx_got_golden.png")),
   207  			delta: -10, // clips to 0.0
   208  			want:  true,
   209  		},
   210  		{
   211  			name:  "png-ok-rgba64-3",
   212  			img1:  asPNG_RGBA64(read("testdata/approx_got_golden.png")),
   213  			img2:  read("testdata/approx_got_golden.png"),
   214  			delta: 0,
   215  			want:  true,
   216  		},
   217  		{
   218  			name:  "png-diff-1",
   219  			img1:  read("testdata/approx_got_golden.png"),
   220  			img2:  read("testdata/approx_want_golden.png"),
   221  			delta: 0,
   222  			want:  false,
   223  		},
   224  		{
   225  			name:  "png-diff-2",
   226  			img1:  read("testdata/approx_got_golden.png"),
   227  			img2:  read("testdata/approx_want_golden.png"),
   228  			delta: 0.01,
   229  			want:  false,
   230  		},
   231  		{
   232  			name:  "png-diff-3",
   233  			img1:  read("testdata/approx_got_golden.png"),
   234  			img2:  read("testdata/good_golden.png"),
   235  			delta: 10, // clips to 1.0
   236  			want:  false,
   237  		},
   238  	} {
   239  		t.Run(tc.name, func(t *testing.T) {
   240  			typ := tc.name[:strings.Index(tc.name, "-")]
   241  			got, err := EqualApprox(typ, tc.img1, tc.img2, tc.delta)
   242  			if err != nil {
   243  				t.Fatalf("could not run equal-approx: %+v", err)
   244  			}
   245  
   246  			if got != tc.want {
   247  				t.Fatalf("invalid equal-approx: got=%v, want=%v", got, tc.want)
   248  			}
   249  		})
   250  	}
   251  }
   252  

View as plain text