tile38/tests/mock_io_test.go

151 lines
2.8 KiB
Go

package tests
import (
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/tidwall/gjson"
)
type IO struct {
args []any
json bool
out any
sleep bool
dur time.Duration
cfile string
cln int
}
func Do(args ...any) *IO {
_, cfile, cln, _ := runtime.Caller(1)
return &IO{args: args, cfile: cfile, cln: cln}
}
func (cmd *IO) JSON() *IO {
cmd.json = true
return cmd
}
func (cmd *IO) Str(s string) *IO {
cmd.out = s
return cmd
}
func (cmd *IO) Func(fn func(s string) error) *IO {
cmd.out = func(s string) error {
if cmd.json {
if !gjson.Valid(s) {
return errors.New("invalid json")
}
}
return fn(s)
}
return cmd
}
func (cmd *IO) OK() *IO {
return cmd.Func(func(s string) error {
if cmd.json {
if gjson.Get(s, "ok").Type != gjson.True {
return errors.New("not ok")
}
} else if s != "OK" {
return errors.New("not ok")
}
return nil
})
}
func (cmd *IO) Err(msg string) *IO {
return cmd.Func(func(s string) error {
if cmd.json {
if gjson.Get(s, "ok").Type != gjson.False {
return errors.New("ok=true")
}
if gjson.Get(s, "err").String() != msg {
return fmt.Errorf("expected '%s', got '%s'",
msg, gjson.Get(s, "err").String())
}
} else {
s = strings.TrimPrefix(s, "ERR ")
if s != msg {
return fmt.Errorf("expected '%s', got '%s'", msg, s)
}
}
return nil
})
}
func Sleep(duration time.Duration) *IO {
return &IO{sleep: true, dur: duration}
}
func (cmd *IO) deepError(index int, err error) error {
frag := "(?)"
bdata, _ := os.ReadFile(cmd.cfile)
data := string(bdata)
ln := 1
for i := 0; i < len(data); i++ {
if data[i] == '\n' {
ln++
if ln == cmd.cln {
data = data[i+1:]
i = strings.IndexByte(data, '(')
if i != -1 {
j := strings.IndexByte(data[i:], ')')
if j != -1 {
frag = string(data[i : j+i+1])
}
}
break
}
}
}
fsig := fmt.Sprintf("%s:%d", filepath.Base(cmd.cfile), cmd.cln)
emsg := err.Error()
if strings.HasPrefix(emsg, "expected ") &&
strings.Contains(emsg, ", got ") {
emsg = "" +
" EXPECTED: " + strings.Split(emsg, ", got ")[0][9:] + "\n" +
" GOT: " +
strings.Split(emsg, ", got ")[1]
} else {
emsg = "" +
" ERROR: " + emsg
}
return fmt.Errorf("\n%s: entry[%d]\n COMMAND: %s\n%s",
fsig, index+1, frag, emsg)
}
func (mc *mockServer) doIOTest(index int, cmd *IO) error {
if cmd.sleep {
time.Sleep(cmd.dur)
return nil
}
// switch json mode if desired
if cmd.json {
if !mc.ioJSON {
if _, err := mc.Do("OUTPUT", "json"); err != nil {
return err
}
mc.ioJSON = true
}
} else {
if mc.ioJSON {
if _, err := mc.Do("OUTPUT", "resp"); err != nil {
return err
}
mc.ioJSON = false
}
}
err := mc.DoExpect(cmd.out, cmd.args[0].(string), cmd.args[1:]...)
if err != nil {
return cmd.deepError(index, err)
}
return nil
}