go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

testutil.go (7880B)


      1 package dbtest
      2 
      3 import (
      4 	"bytes"
      5 	"context"
      6 	"encoding/hex"
      7 	"errors"
      8 	"fmt"
      9 	"path"
     10 	"testing"
     11 
     12 	"git.defalsify.org/vise.git/db"
     13 	"git.defalsify.org/vise.git/lang"
     14 )
     15 
     16 type testCase struct {
     17 	typ uint8
     18 	s   string
     19 	k   []byte
     20 	v   []byte
     21 	x   []byte
     22 	l   *lang.Language
     23 	t   string
     24 }
     25 
     26 type testVector struct {
     27 	c map[string]*testCase
     28 	v []string
     29 	i int
     30 	s string
     31 }
     32 
     33 type testFunc func() testVector
     34 
     35 var (
     36 	tests = []testFunc{
     37 		generateSessionTestVectors,
     38 		generateMultiSessionTestVectors,
     39 		generateLanguageTestVectors,
     40 		generateMultiLanguageTestVectors,
     41 		generateSessionLanguageTestVectors,
     42 	}
     43 	dataTypeDebug = map[uint8]string{
     44 		db.DATATYPE_BIN:        "bytecode",
     45 		db.DATATYPE_TEMPLATE:   "template",
     46 		db.DATATYPE_MENU:       "menu",
     47 		db.DATATYPE_STATICLOAD: "staticload",
     48 		db.DATATYPE_STATE:      "state",
     49 		db.DATATYPE_USERDATA:   "udata",
     50 	}
     51 )
     52 
     53 func (tc *testCase) Key() []byte {
     54 	return tc.k
     55 }
     56 
     57 func (tc *testCase) Val() []byte {
     58 	return tc.v
     59 }
     60 
     61 func (tc *testCase) Typ() uint8 {
     62 	return tc.typ
     63 }
     64 
     65 func (tc *testCase) Session() string {
     66 	return tc.s
     67 }
     68 
     69 func (tc *testCase) Lang() string {
     70 	if tc.l == nil {
     71 		return ""
     72 	}
     73 	return tc.l.Code
     74 }
     75 
     76 func (tc *testCase) Expect() []byte {
     77 	return tc.x
     78 }
     79 
     80 func (tc *testCase) Label() string {
     81 	return tc.t
     82 }
     83 
     84 func (tv *testVector) add(typ uint8, k string, v string, session string, expect string, language string) {
     85 	var b []byte
     86 	var x []byte
     87 	var err error
     88 	var ln *lang.Language
     89 
     90 	if typ == db.DATATYPE_BIN {
     91 		b, err = hex.DecodeString(v)
     92 		if err != nil {
     93 			panic(err)
     94 		}
     95 		x, err = hex.DecodeString(expect)
     96 		if err != nil {
     97 			panic(err)
     98 		}
     99 	} else {
    100 		b = []byte(v)
    101 		x = []byte(expect)
    102 	}
    103 
    104 	if language != "" {
    105 		lo, err := lang.LanguageFromCode(language)
    106 		if err != nil {
    107 			panic(err)
    108 		}
    109 		ln = &lo
    110 	}
    111 	s := dataTypeDebug[typ]
    112 	s = path.Join(s, session)
    113 	s = path.Join(s, k)
    114 	if ln != nil {
    115 		s = path.Join(s, language)
    116 	}
    117 	o := &testCase{
    118 		typ: typ,
    119 		k:   []byte(k),
    120 		v:   b,
    121 		s:   session,
    122 		x:   x,
    123 		l:   ln,
    124 		t:   s,
    125 	}
    126 	tv.c[s] = o
    127 	i := len(tv.v)
    128 	tv.v = append(tv.v, s)
    129 	logg.Tracef("add testcase", "i", i, "s", s, "k", o.k)
    130 }
    131 
    132 func (tv *testVector) next() (int, *testCase) {
    133 	i := tv.i
    134 	if i == len(tv.v) {
    135 		return -1, nil
    136 	}
    137 	tv.i++
    138 	return i, tv.c[tv.v[i]]
    139 }
    140 
    141 func (tv *testVector) rewind() {
    142 	tv.i = 0
    143 }
    144 
    145 func (tv *testVector) put(ctx context.Context, db db.Db) error {
    146 	var i int
    147 	var tc *testCase
    148 	defer tv.rewind()
    149 
    150 	for true {
    151 		i, tc = tv.next()
    152 		if i == -1 {
    153 			break
    154 		}
    155 		logg.TraceCtxf(ctx, "running put for test", "vector", tv.label(), "case", tc.Label())
    156 		db.SetPrefix(tc.Typ())
    157 		db.SetSession(tc.Session())
    158 		db.SetLock(tc.Typ(), false)
    159 		db.SetLanguage(nil)
    160 		if tc.Lang() != "" {
    161 			ln, err := lang.LanguageFromCode(tc.Lang())
    162 			if err != nil {
    163 				return err
    164 			}
    165 			db.SetLanguage(&ln)
    166 		}
    167 		err := db.Put(ctx, tc.Key(), tc.Val())
    168 		if err != nil {
    169 			return err
    170 		}
    171 		db.SetLock(tc.Typ(), true)
    172 	}
    173 	return nil
    174 }
    175 
    176 func (tv *testVector) label() string {
    177 	return tv.s
    178 }
    179 
    180 func generateSessionTestVectors() testVector {
    181 	tv := testVector{c: make(map[string]*testCase), s: "session"}
    182 	tv.add(db.DATATYPE_BIN, "foo", "deadbeef", "", "beeffeed", "")
    183 	tv.add(db.DATATYPE_BIN, "foo", "beeffeed", "inky", "beeffeed", "")
    184 	tv.add(db.DATATYPE_TEMPLATE, "foo", "tinkywinky", "", "dipsy", "")
    185 	tv.add(db.DATATYPE_TEMPLATE, "foo", "dipsy", "pinky", "dipsy", "")
    186 	tv.add(db.DATATYPE_MENU, "foo", "lala", "", "pu", "")
    187 	tv.add(db.DATATYPE_MENU, "foo", "pu", "blinky", "pu", "")
    188 	tv.add(db.DATATYPE_STATICLOAD, "foo", "bar", "", "baz", "")
    189 	tv.add(db.DATATYPE_STATICLOAD, "foo", "baz", "clyde", "baz", "")
    190 	tv.add(db.DATATYPE_STATE, "foo", "xyzzy", "", "xyzzy", "")
    191 	tv.add(db.DATATYPE_STATE, "foo", "plugh", "sue", "plugh", "")
    192 	tv.add(db.DATATYPE_USERDATA, "foo", "itchy", "", "itchy", "")
    193 	tv.add(db.DATATYPE_USERDATA, "foo", "scratchy", "poochie", "scratchy", "")
    194 	return tv
    195 }
    196 
    197 func generateLanguageTestVectors() testVector {
    198 	tv := testVector{c: make(map[string]*testCase), s: "language"}
    199 	tv.add(db.DATATYPE_BIN, "foo", "deadbeef", "", "beeffeed", "")
    200 	tv.add(db.DATATYPE_BIN, "foo", "beeffeed", "", "beeffeed", "nor")
    201 	tv.add(db.DATATYPE_TEMPLATE, "foo", "tinkywinky", "", "tinkywinky", "")
    202 	tv.add(db.DATATYPE_TEMPLATE, "foo", "dipsy", "", "dipsy", "nor")
    203 	tv.add(db.DATATYPE_MENU, "foo", "lala", "", "lala", "")
    204 	tv.add(db.DATATYPE_MENU, "foo", "pu", "", "pu", "nor")
    205 	tv.add(db.DATATYPE_STATICLOAD, "foo", "bar", "", "bar", "")
    206 	tv.add(db.DATATYPE_STATICLOAD, "foo", "baz", "", "baz", "nor")
    207 	tv.add(db.DATATYPE_STATE, "foo", "xyzzy", "", "plugh", "")
    208 	tv.add(db.DATATYPE_STATE, "foo", "plugh", "", "plugh", "nor")
    209 	tv.add(db.DATATYPE_USERDATA, "foo", "itchy", "", "scratchy", "")
    210 	tv.add(db.DATATYPE_USERDATA, "foo", "scratchy", "", "scratchy", "nor")
    211 	return tv
    212 }
    213 
    214 func generateMultiLanguageTestVectors() testVector {
    215 	tv := testVector{c: make(map[string]*testCase), s: "multilanguage"}
    216 	tv.add(db.DATATYPE_TEMPLATE, "foo", "tinkywinky", "", "pu", "")
    217 	tv.add(db.DATATYPE_TEMPLATE, "foo", "dipsy", "", "dipsy", "nor")
    218 	tv.add(db.DATATYPE_TEMPLATE, "foo", "lala", "", "lala", "swa")
    219 	tv.add(db.DATATYPE_TEMPLATE, "foo", "pu", "", "pu", "")
    220 	return tv
    221 }
    222 
    223 func generateSessionLanguageTestVectors() testVector {
    224 	tv := testVector{c: make(map[string]*testCase), s: "sessionlanguage"}
    225 	tv.add(db.DATATYPE_TEMPLATE, "foo", "tinkywinky", "", "pu", "")
    226 	tv.add(db.DATATYPE_TEMPLATE, "foo", "dipsy", "", "lala", "nor")
    227 	tv.add(db.DATATYPE_TEMPLATE, "foo", "lala", "bar", "lala", "nor")
    228 	tv.add(db.DATATYPE_TEMPLATE, "foo", "pu", "bar", "pu", "")
    229 	tv.add(db.DATATYPE_STATE, "foo", "inky", "", "pinky", "")
    230 	tv.add(db.DATATYPE_STATE, "foo", "pinky", "", "pinky", "nor")
    231 	tv.add(db.DATATYPE_STATE, "foo", "blinky", "bar", "clyde", "nor")
    232 	tv.add(db.DATATYPE_STATE, "foo", "clyde", "bar", "clyde", "")
    233 	tv.add(db.DATATYPE_BIN, "foo", "deadbeef", "", "feebdaed", "")
    234 	tv.add(db.DATATYPE_BIN, "foo", "beeffeed", "", "feebdaed", "nor")
    235 	tv.add(db.DATATYPE_BIN, "foo", "deeffeeb", "baz", "feebdaed", "nor")
    236 	tv.add(db.DATATYPE_BIN, "foo", "feebdaed", "baz", "feebdaed", "")
    237 	return tv
    238 }
    239 
    240 func generateMultiSessionTestVectors() testVector {
    241 	tv := testVector{c: make(map[string]*testCase), s: "multisession"}
    242 	tv.add(db.DATATYPE_TEMPLATE, "foo", "red", "", "blue", "")
    243 	tv.add(db.DATATYPE_TEMPLATE, "foo", "green", "bar", "blue", "")
    244 	tv.add(db.DATATYPE_TEMPLATE, "foo", "blue", "baz", "blue", "")
    245 	tv.add(db.DATATYPE_STATE, "foo", "inky", "", "inky", "")
    246 	tv.add(db.DATATYPE_STATE, "foo", "pinky", "clyde", "pinky", "")
    247 	tv.add(db.DATATYPE_STATE, "foo", "blinky", "sue", "blinky", "")
    248 	tv.add(db.DATATYPE_BIN, "foo", "deadbeef", "", "feebdeef", "")
    249 	tv.add(db.DATATYPE_BIN, "foo", "feedbeef", "bar", "feebdeef", "")
    250 	tv.add(db.DATATYPE_BIN, "foo", "feebdeef", "baz", "feebdeef", "")
    251 	return tv
    252 }
    253 
    254 func runTest(t *testing.T, ctx context.Context, db db.Db, vs testVector) error {
    255 	err := vs.put(ctx, db)
    256 	if err != nil {
    257 		return err
    258 	}
    259 	for true {
    260 		i, tc := vs.next()
    261 		if i == -1 {
    262 			break
    263 		}
    264 		s := fmt.Sprintf("Test%s[%d]%s", vs.label(), i, tc.Label())
    265 		r := t.Run(s, func(t *testing.T) {
    266 			db.SetPrefix(tc.Typ())
    267 			db.SetSession(tc.Session())
    268 			if tc.Lang() != "" {
    269 				ln, err := lang.LanguageFromCode(tc.Lang())
    270 				if err != nil {
    271 					t.Fatal(err)
    272 				}
    273 				db.SetLanguage(&ln)
    274 			} else {
    275 				db.SetLanguage(nil)
    276 			}
    277 			db.SetSession(tc.Session())
    278 			v, err := db.Get(ctx, tc.Key())
    279 			if err != nil {
    280 				t.Fatal(err)
    281 			}
    282 			if !bytes.Equal(tc.Expect(), v) {
    283 				t.Fatalf("expected %s, got %s", tc.Expect(), v)
    284 			}
    285 		})
    286 		if !r {
    287 			return errors.New("subtest fail")
    288 		}
    289 	}
    290 	return nil
    291 
    292 }
    293 
    294 func runTests(t *testing.T, ctx context.Context, db db.Db) error {
    295 	for _, fn := range tests {
    296 		err := runTest(t, ctx, db, fn())
    297 		if err != nil {
    298 			return err
    299 		}
    300 	}
    301 
    302 	return nil
    303 }
    304 
    305 func RunTests(t *testing.T, ctx context.Context, db db.Db) error {
    306 	return runTests(t, ctx, db)
    307 }