github.com/lino-network/lino@v0.6.11/testsuites/golden.go (about)

     1  package testsuites
     2  
     3  import (
     4  	"encoding/json"
     5  	"flag"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"sort"
    10  	"strings"
    11  	"time"
    12  
    13  	sdk "github.com/cosmos/cosmos-sdk/types"
    14  	"github.com/lino-network/lino/testutils"
    15  )
    16  
    17  var update = flag.Bool("update", false, "update .golden files")
    18  
    19  type dumperManager interface {
    20  	NewDumper() *testutils.Dumper
    21  }
    22  
    23  type GoldenTestSuite struct {
    24  	CtxTestSuite
    25  	dm       dumperManager
    26  	storeKey *sdk.KVStoreKey
    27  }
    28  
    29  func NewGoldenTestSuite(dm dumperManager, storeKey *sdk.KVStoreKey) GoldenTestSuite {
    30  	return GoldenTestSuite{
    31  		dm:       dm,
    32  		storeKey: storeKey,
    33  	}
    34  }
    35  
    36  func (suite *GoldenTestSuite) LoadState(enableSubTest bool, importJsonPaths ...string) {
    37  	// Maybe we shouldn't SetupCtx but only reset the store here.
    38  	suite.SetupCtx(suite.height, time.Unix(0, 0), suite.storeKey)
    39  	if suite.dm == nil {
    40  		suite.FailNow("Should register a dumpManager before calling LoadState")
    41  	}
    42  	d := suite.dm.NewDumper()
    43  	t := suite.T()
    44  	name := t.Name()
    45  	parentName := name[:strings.LastIndex(name, "/")]
    46  
    47  	var fileName string
    48  	if enableSubTest {
    49  		fileName = name
    50  	} else {
    51  		fileName = parentName
    52  	}
    53  
    54  	gp := filepath.Join("input", fileName+".input")
    55  	if fileExists(gp) {
    56  		d.LoadFromFile(suite.Ctx, gp)
    57  	}
    58  	for _, path := range importJsonPaths {
    59  		gp := filepath.Join("input", "common", path+".input")
    60  		d.LoadFromFile(suite.Ctx, gp)
    61  	}
    62  }
    63  
    64  // XXX(@ryanli): Maybe we use delta for golden, better readability
    65  func (suite *GoldenTestSuite) Golden() {
    66  	if suite.dm == nil {
    67  		suite.FailNow("Should register a dumpManager before calling Golden")
    68  	}
    69  	d := suite.dm.NewDumper()
    70  	b := d.ToJSON(suite.Ctx)
    71  	// Add a newline character at the end of file
    72  	b = append(b, '\n')
    73  	t := suite.T()
    74  	gp := filepath.Join("golden", t.Name()+".golden")
    75  	dir, _ := filepath.Split(gp)
    76  	err := ensureDir(dir)
    77  	suite.NoError(err)
    78  	if *update {
    79  		err := ioutil.WriteFile(gp, b, 0644)
    80  		suite.NoError(err)
    81  	}
    82  	g, err := ioutil.ReadFile(gp)
    83  	suite.NoError(err)
    84  	suite.Equal(b, g)
    85  }
    86  
    87  func (suite *GoldenTestSuite) AssertStateUnchanged(enableSubTest bool, importJsonPaths ...string) {
    88  	t := suite.T()
    89  	name := t.Name()
    90  	parentName := name[:strings.LastIndex(name, "/")]
    91  	var fileName string
    92  	if enableSubTest {
    93  		fileName = name
    94  	} else {
    95  		fileName = parentName
    96  	}
    97  	gp := filepath.Join("input", fileName+".input")
    98  	states := make(testutils.JSONState, 0)
    99  	if fileExists(gp) {
   100  		input, err := ioutil.ReadFile(gp)
   101  		suite.NoError(err)
   102  		err = json.Unmarshal(input, &states)
   103  		suite.NoError(err)
   104  	}
   105  
   106  	for _, p := range importJsonPaths {
   107  		tmp := make(testutils.JSONState, 0)
   108  		gp := filepath.Join("input", "common", p+".input")
   109  		input, err := ioutil.ReadFile(gp)
   110  		suite.NoError(err)
   111  		err = json.Unmarshal(input, &tmp)
   112  		suite.NoError(err)
   113  		states = append(states, tmp...)
   114  	}
   115  
   116  	// sort by prefix and then key
   117  	sort.Slice(states, func(i, j int) bool {
   118  		return states[i].Prefix < states[j].Prefix ||
   119  			(states[i].Prefix == states[j].Prefix && states[i].Key < states[j].Key)
   120  	})
   121  
   122  	inputStates, err := json.Marshal(states)
   123  	suite.NoError(err)
   124  
   125  	gp = filepath.Join("golden", t.Name()+".golden")
   126  	suite.NoError(err)
   127  	golden, err := ioutil.ReadFile(gp)
   128  	suite.NoError(err)
   129  	suite.JSONEq(string(inputStates), string(golden))
   130  }
   131  
   132  func ensureDir(dirName string) error {
   133  	err := os.MkdirAll(dirName, 0700)
   134  	if err == nil || os.IsExist(err) {
   135  		return nil
   136  	} else {
   137  		return err
   138  	}
   139  }
   140  
   141  func fileExists(filename string) bool {
   142  	info, err := os.Stat(filename)
   143  	if os.IsNotExist(err) {
   144  		return false
   145  	}
   146  	return !info.IsDir()
   147  }