gonum.org/v1/gonum@v0.14.0/graph/layout/layout_test.go (about)

     1  // Copyright ©2019 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 layout_test
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/base64"
    10  	"image"
    11  	"image/png"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  	"testing"
    16  
    17  	"gonum.org/v1/gonum/graph"
    18  	"gonum.org/v1/gonum/graph/internal/ordered"
    19  	"gonum.org/v1/gonum/graph/iterator"
    20  	"gonum.org/v1/plot/cmpimg"
    21  )
    22  
    23  // orderedGraph wraps a graph.Graph ensuring consistent ordering of nodes
    24  // in graph queries. Removal of this causes to tests to fail due to changes
    25  // in node iteration order, but the produced graph layouts are still good.
    26  type orderedGraph struct {
    27  	graph.Graph
    28  }
    29  
    30  func (g orderedGraph) Nodes() graph.Nodes {
    31  	n := graph.NodesOf(g.Graph.Nodes())
    32  	ordered.ByID(n)
    33  	return iterator.NewOrderedNodes(n)
    34  }
    35  
    36  func (g orderedGraph) From(id int64) graph.Nodes {
    37  	n := graph.NodesOf(g.Graph.From(id))
    38  	ordered.ByID(n)
    39  	return iterator.NewOrderedNodes(n)
    40  }
    41  
    42  func goldenPath(path string) string {
    43  	ext := filepath.Ext(path)
    44  	noext := strings.TrimSuffix(path, ext)
    45  	return noext + "_golden" + ext
    46  }
    47  
    48  func checkRenderedLayout(t *testing.T, path string) (ok bool) {
    49  	if *cmpimg.GenerateTestData {
    50  		// Recreate Golden image and exit.
    51  		golden := goldenPath(path)
    52  		_ = os.Remove(golden)
    53  		if err := os.Rename(path, golden); err != nil {
    54  			t.Fatal(err)
    55  		}
    56  		return true
    57  	}
    58  
    59  	// Read the images we've just generated and check them against the
    60  	// Golden Images.
    61  	got, err := os.ReadFile(path)
    62  	if err != nil {
    63  		t.Errorf("failed to read %s: %v", path, err)
    64  		return true
    65  	}
    66  	golden := goldenPath(path)
    67  	want, err := os.ReadFile(golden)
    68  	if err != nil {
    69  		t.Errorf("failed to read golden file %s: %v", golden, err)
    70  		return true
    71  	}
    72  	typ := filepath.Ext(path)[1:] // remove the dot in ".png"
    73  	ok, err = cmpimg.Equal(typ, got, want)
    74  	if err != nil {
    75  		t.Errorf("failed to compare image for %s: %v", path, err)
    76  		return true
    77  	}
    78  	if !ok {
    79  		t.Errorf("image mismatch for %s\n", path)
    80  		v1, _, err := image.Decode(bytes.NewReader(got))
    81  		if err != nil {
    82  			t.Errorf("failed to decode %s: %v", path, err)
    83  			return false
    84  		}
    85  		v2, _, err := image.Decode(bytes.NewReader(want))
    86  		if err != nil {
    87  			t.Errorf("failed to decode %s: %v", golden, err)
    88  			return false
    89  		}
    90  
    91  		dst := image.NewRGBA64(v1.Bounds().Union(v2.Bounds()))
    92  		rect := cmpimg.Diff(dst, v1, v2)
    93  		t.Logf("image bounds union:%+v diff bounds intersection:%+v", dst.Bounds(), rect)
    94  
    95  		var buf bytes.Buffer
    96  		err = png.Encode(&buf, dst)
    97  		if err != nil {
    98  			t.Errorf("failed to encode difference png: %v", err)
    99  			return false
   100  		}
   101  		t.Log("IMAGE:" + base64.StdEncoding.EncodeToString(buf.Bytes()))
   102  	}
   103  	return ok
   104  }