Add more tests
This commit is contained in:
parent
bdad1299c4
commit
d9356a48a5
52
expr_test.go
52
expr_test.go
@ -1,9 +1,7 @@
|
|||||||
package salix
|
package salix
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAdd(t *testing.T) {
|
func TestAdd(t *testing.T) {
|
||||||
@ -139,59 +137,9 @@ func TestNot(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIndex(t *testing.T) {
|
|
||||||
res := execStr(t, `#(x[0]) #(y["hello"])`, map[string]any{
|
|
||||||
"x": []int{0, 1, 2},
|
|
||||||
"y": map[string]string{"hello": "world"},
|
|
||||||
})
|
|
||||||
if res != "0 world" {
|
|
||||||
t.Errorf("Expected %q, got %q", "equal non-equal", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFuncCall(t *testing.T) {
|
|
||||||
res := execStr(t, `#(toUpper("hello"))`, nil)
|
|
||||||
if res != "HELLO" {
|
|
||||||
t.Errorf("Expected %q, got %q", "HELLO", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAssignment(t *testing.T) {
|
func TestAssignment(t *testing.T) {
|
||||||
res := execStr(t, `#(x = 4)#(x)`, nil)
|
res := execStr(t, `#(x = 4)#(x)`, nil)
|
||||||
if res != "4" {
|
if res != "4" {
|
||||||
t.Errorf("Expected %q, got %q", "4", res)
|
t.Errorf("Expected %q, got %q", "4", res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMethodCall(t *testing.T) {
|
|
||||||
res := execStr(t, `#(t.String())`, map[string]any{
|
|
||||||
"t": time.Date(2023, time.April, 26, 0, 0, 0, 0, time.UTC),
|
|
||||||
})
|
|
||||||
if res != "2023-04-26 00:00:00 +0000 UTC" {
|
|
||||||
t.Errorf("Expected %q, got %q", "2023-04-26 00:00:00 +0000 UTC", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVariadic(t *testing.T) {
|
|
||||||
res := execStr(t, `#(sprintf("%s %d", x, y))`, map[string]any{
|
|
||||||
"x": "test",
|
|
||||||
"y": 4,
|
|
||||||
})
|
|
||||||
if res != "test 4" {
|
|
||||||
t.Errorf("Expected %q, got %q", "test 4", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func execStr(t *testing.T, tmplStr string, vars map[string]any) string {
|
|
||||||
t.Helper()
|
|
||||||
tmpl, err := New().ParseString("test", tmplStr)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
sb := &strings.Builder{}
|
|
||||||
err = tmpl.WithVarMap(vars).Execute(sb)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
return sb.String()
|
|
||||||
}
|
|
||||||
|
124
func_test.go
Normal file
124
func_test.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package salix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.elara.ws/salix/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFuncCall(t *testing.T) {
|
||||||
|
const expected = 1 + 2i
|
||||||
|
fn := func() complex128 { return expected }
|
||||||
|
|
||||||
|
// test()
|
||||||
|
ast := ast.FuncCall{
|
||||||
|
Name: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
val, err := tmpl.execFuncCall(ast, map[string]any{"test": fn})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("execFuncCall error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if val.(complex128) != expected {
|
||||||
|
t.Errorf("Expected %v, got %v", expected, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFuncCallVariadic(t *testing.T) {
|
||||||
|
const expected = "Hello, World"
|
||||||
|
concat := func(params ...string) string { return strings.Join(params, ", ") }
|
||||||
|
|
||||||
|
// concat("Hello", "World")
|
||||||
|
ast := ast.FuncCall{
|
||||||
|
Name: ast.Ident{Value: "concat", Position: testPos(t)},
|
||||||
|
Params: []ast.Node{
|
||||||
|
ast.String{Value: "Hello", Position: testPos(t)},
|
||||||
|
ast.String{Value: "World", Position: testPos(t)},
|
||||||
|
},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
val, err := tmpl.execFuncCall(ast, map[string]any{"concat": concat})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("execFuncCall error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if val.(string) != expected {
|
||||||
|
t.Errorf("Expected %q, got %q", expected, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFuncCallError(t *testing.T) {
|
||||||
|
var expectedErr = errors.New("expected error")
|
||||||
|
fn := func() error { return expectedErr }
|
||||||
|
|
||||||
|
// test()
|
||||||
|
ast := ast.FuncCall{
|
||||||
|
Name: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
_, err := tmpl.execFuncCall(ast, map[string]any{"test": fn})
|
||||||
|
if !errors.Is(err, expectedErr) {
|
||||||
|
t.Errorf("Expected %q, got %q", expectedErr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFuncCallMultiReturn(t *testing.T) {
|
||||||
|
const expected = "test"
|
||||||
|
fn := func() (string, error) { return expected, nil }
|
||||||
|
|
||||||
|
// test()
|
||||||
|
ast := ast.FuncCall{
|
||||||
|
Name: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
val, err := tmpl.execFuncCall(ast, map[string]any{"test": fn})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("execFuncCall error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if val.(string) != expected {
|
||||||
|
t.Errorf("Expected %q, got %q", expected, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFuncCallMultiReturnError(t *testing.T) {
|
||||||
|
var expectedErr = errors.New("expected error")
|
||||||
|
fn := func() (string, error) { return "", expectedErr }
|
||||||
|
|
||||||
|
// test()
|
||||||
|
ast := ast.FuncCall{
|
||||||
|
Name: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
_, err := tmpl.execFuncCall(ast, map[string]any{"test": fn})
|
||||||
|
if !errors.Is(err, expectedErr) {
|
||||||
|
t.Errorf("Expected %q, got %q", expectedErr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFuncCallNil(t *testing.T) {
|
||||||
|
// test()
|
||||||
|
ast := ast.FuncCall{
|
||||||
|
Name: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
_, err := tmpl.execFuncCall(ast, map[string]any{"test": nil})
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error, got nil")
|
||||||
|
}
|
||||||
|
}
|
248
structs_test.go
Normal file
248
structs_test.go
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
package salix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.elara.ws/salix/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSliceGetIndex(t *testing.T) {
|
||||||
|
testSlice := []any{1, "2", 3.0}
|
||||||
|
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
for index, expected := range testSlice {
|
||||||
|
t.Run(fmt.Sprint(index), func(t *testing.T) {
|
||||||
|
// test[index]
|
||||||
|
ast := ast.Index{
|
||||||
|
Value: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Index: ast.Ident{Value: "index", Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := tmpl.getIndex(ast, map[string]any{"test": testSlice, "index": index})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("getIndex error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if val != expected {
|
||||||
|
t.Errorf("Expected %v, got %v", expected, val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSliceGetIndexOutOfRange(t *testing.T) {
|
||||||
|
testSlice := []any{}
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
|
||||||
|
// test[0.0]
|
||||||
|
ast := ast.Index{
|
||||||
|
Value: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Index: ast.Float{Value: 0, Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := tmpl.getIndex(ast, map[string]any{"test": testSlice})
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected error, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapGetIndex(t *testing.T) {
|
||||||
|
testMap := map[any]any{1: "2", 3.0: 4, "5": 6.0}
|
||||||
|
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
for index, expected := range testMap {
|
||||||
|
t.Run(fmt.Sprint(index), func(t *testing.T) {
|
||||||
|
// test[index]
|
||||||
|
ast := ast.Index{
|
||||||
|
Value: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Index: ast.Ident{Value: "index", Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := tmpl.getIndex(ast, map[string]any{"test": testMap, "index": index})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("getIndex error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if val != expected {
|
||||||
|
t.Errorf("Expected %v, got %v", expected, val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapGetIndexNotFound(t *testing.T) {
|
||||||
|
testMap := map[string]any{}
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
|
||||||
|
// test["key"]
|
||||||
|
ast := ast.Index{
|
||||||
|
Value: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Index: ast.String{Value: "key", Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := tmpl.getIndex(ast, map[string]any{"test": testMap})
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetIndexNil(t *testing.T) {
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
|
||||||
|
// test["key"]
|
||||||
|
ast := ast.Index{
|
||||||
|
Value: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Index: ast.String{Value: "key", Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := tmpl.getIndex(ast, map[string]any{"test": nil})
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetField(t *testing.T) {
|
||||||
|
testStruct := struct {
|
||||||
|
X int
|
||||||
|
Y string
|
||||||
|
Z struct{ A int }
|
||||||
|
}{
|
||||||
|
X: 1,
|
||||||
|
Y: "2",
|
||||||
|
Z: struct{ A int }{A: 1},
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := map[string]any{
|
||||||
|
"X": testStruct.X,
|
||||||
|
"Y": testStruct.Y,
|
||||||
|
"Z": testStruct.Z,
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
for fieldName, expected := range testCases {
|
||||||
|
t.Run(fieldName, func(t *testing.T) {
|
||||||
|
// test.Field
|
||||||
|
ast := ast.FieldAccess{
|
||||||
|
Value: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Name: ast.Ident{Value: fieldName, Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := tmpl.getField(ast, map[string]any{"test": testStruct})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("getField error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if val != expected {
|
||||||
|
t.Errorf("Expected %v, got %v", expected, val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFieldNotFound(t *testing.T) {
|
||||||
|
testStruct := struct{}{}
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
|
||||||
|
// test.Field
|
||||||
|
ast := ast.FieldAccess{
|
||||||
|
Value: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Name: ast.Ident{Value: "Field", Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := tmpl.getField(ast, map[string]any{"test": testStruct})
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFieldNil(t *testing.T) {
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
|
||||||
|
// test.Field
|
||||||
|
ast := ast.FieldAccess{
|
||||||
|
Value: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Name: ast.Ident{Value: "Field", Position: testPos(t)},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := tmpl.getField(ast, map[string]any{"test": nil})
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMethodCall(t *testing.T) {
|
||||||
|
executed := false
|
||||||
|
testStruct := struct{ Method func(bool) bool }{
|
||||||
|
Method: func(b bool) bool {
|
||||||
|
executed = b
|
||||||
|
return executed
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// test.Method(true)
|
||||||
|
ast := ast.MethodCall{
|
||||||
|
Value: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Name: ast.Ident{Value: "Method", Position: testPos(t)},
|
||||||
|
Params: []ast.Node{
|
||||||
|
ast.Bool{Value: true, Position: testPos(t)},
|
||||||
|
},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
val, err := tmpl.execMethodCall(ast, map[string]any{"test": testStruct})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("execMethodCall error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !executed || !val.(bool) {
|
||||||
|
t.Error("Expected method to execute, got false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMethodCallNotFound(t *testing.T) {
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
|
||||||
|
// test.Method(true)
|
||||||
|
ast := ast.MethodCall{
|
||||||
|
Value: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Name: ast.Ident{Value: "Method", Position: testPos(t)},
|
||||||
|
Params: []ast.Node{
|
||||||
|
ast.Bool{Value: true, Position: testPos(t)},
|
||||||
|
},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := tmpl.execMethodCall(ast, map[string]any{"test": struct{}{}})
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMethodCallNil(t *testing.T) {
|
||||||
|
tmpl := testTmpl(t)
|
||||||
|
|
||||||
|
// test.Method(true)
|
||||||
|
ast := ast.MethodCall{
|
||||||
|
Value: ast.Ident{Value: "test", Position: testPos(t)},
|
||||||
|
Name: ast.Ident{Value: "Method", Position: testPos(t)},
|
||||||
|
Params: []ast.Node{
|
||||||
|
ast.Bool{Value: true, Position: testPos(t)},
|
||||||
|
},
|
||||||
|
Position: testPos(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := tmpl.execMethodCall(ast, map[string]any{"test": nil})
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error, got nil")
|
||||||
|
}
|
||||||
|
}
|
48
test_utils.go
Normal file
48
test_utils.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package salix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.elara.ws/salix/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testTmpl(t *testing.T) Template {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
return Template{
|
||||||
|
ns: &Namespace{
|
||||||
|
tmpls: map[string]Template{},
|
||||||
|
tags: map[string]Tag{},
|
||||||
|
vars: map[string]any{},
|
||||||
|
},
|
||||||
|
name: t.Name(),
|
||||||
|
tags: map[string]Tag{},
|
||||||
|
vars: map[string]any{},
|
||||||
|
macros: map[string][]ast.Node{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPos(t *testing.T) ast.Position {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
return ast.Position{
|
||||||
|
Name: t.Name(),
|
||||||
|
Line: -1,
|
||||||
|
Col: -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func execStr(t *testing.T, tmplStr string, vars map[string]any) string {
|
||||||
|
t.Helper()
|
||||||
|
tmpl, err := New().ParseString("test", tmplStr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
sb := &strings.Builder{}
|
||||||
|
err = tmpl.WithVarMap(vars).Execute(sb)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user