...

Source file src/github.com/noirbizarre/gonja/exec/value_test.go

Documentation: github.com/noirbizarre/gonja/exec

     1  package exec_test
     2  
     3  import (
     4  	// "fmt"
     5  
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/noirbizarre/gonja/exec"
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  type flags struct {
    14  	IsString   bool
    15  	IsCallable bool
    16  	IsBool     bool
    17  	IsFloat    bool
    18  	IsInteger  bool
    19  	IsNumber   bool
    20  	IsList     bool
    21  	IsDict     bool
    22  	IsIterable bool
    23  	IsNil      bool
    24  	IsTrue     bool
    25  	IsError    bool
    26  }
    27  
    28  func (f *flags) assert(t *testing.T, value *exec.Value) {
    29  	assert := assert.New(t)
    30  
    31  	val := reflect.ValueOf(value)
    32  	fval := reflect.ValueOf(f).Elem()
    33  
    34  	for i := 0; i < fval.NumField(); i++ {
    35  		name := fval.Type().Field(i).Name
    36  		method := val.MethodByName(name)
    37  		bVal := fval.Field(i).Interface().(bool)
    38  		result := method.Call([]reflect.Value{})
    39  		bResult := result[0].Interface().(bool)
    40  		if bVal {
    41  			assert.Truef(bResult, `%s() should be true`, name)
    42  		} else {
    43  			assert.Falsef(bResult, `%s() should be false`, name)
    44  		}
    45  	}
    46  }
    47  
    48  var valueCases = []struct {
    49  	name     string
    50  	value    interface{}
    51  	asString string
    52  	flags    flags
    53  }{
    54  	{"nil", nil, "", flags{IsNil: true}},
    55  	{"string", "Hello World", "Hello World", flags{IsString: true, IsTrue: true, IsIterable: true}},
    56  	{"int", 42, "42", flags{IsInteger: true, IsNumber: true, IsTrue: true}},
    57  	{"int 0", 0, "0", flags{IsInteger: true, IsNumber: true}},
    58  	{"float", 42., "42.0", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
    59  	{"float with trailing zeros", 42.04200, "42.042", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
    60  	{"float max precision", 42.5556700089099, "42.55567000891", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
    61  	{"float max precision rounded up", 42.555670008999999, "42.555670009", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
    62  	{"float 0.0", 0., "0.0", flags{IsFloat: true, IsNumber: true}},
    63  	{"true", true, "True", flags{IsBool: true, IsTrue: true}},
    64  	{"false", false, "False", flags{IsBool: true}},
    65  	{"slice", []int{1, 2, 3}, "[1, 2, 3]", flags{IsTrue: true, IsIterable: true, IsList: true}},
    66  	{"strings slice", []string{"a", "b", "c"}, "['a', 'b', 'c']", flags{IsTrue: true, IsIterable: true, IsList: true}},
    67  	{
    68  		"values slice",
    69  		[]*exec.Value{exec.AsValue(1), exec.AsValue(2), exec.AsValue(3)},
    70  		"[1, 2, 3]",
    71  		flags{IsTrue: true, IsIterable: true, IsList: true},
    72  	},
    73  	{"string values slice",
    74  		[]*exec.Value{exec.AsValue("a"), exec.AsValue("b"), exec.AsValue("c")},
    75  		"['a', 'b', 'c']",
    76  		flags{IsTrue: true, IsIterable: true, IsList: true},
    77  	},
    78  	{"array", [3]int{1, 2, 3}, "[1, 2, 3]", flags{IsTrue: true, IsIterable: true, IsList: true}},
    79  	{"strings array", [3]string{"a", "b", "c"}, "['a', 'b', 'c']", flags{IsTrue: true, IsIterable: true, IsList: true}},
    80  	{
    81  		"dict as map",
    82  		map[string]string{"a": "a", "b": "b"},
    83  		"{'a': 'a', 'b': 'b'}",
    84  		flags{IsTrue: true, IsIterable: true, IsDict: true},
    85  	},
    86  	{
    87  		"dict as Dict/Pairs",
    88  		&exec.Dict{[]*exec.Pair{
    89  			{exec.AsValue("a"), exec.AsValue("a")},
    90  			{exec.AsValue("b"), exec.AsValue("b")},
    91  		}},
    92  		"{'a': 'a', 'b': 'b'}",
    93  		flags{IsTrue: true, IsIterable: true, IsDict: true},
    94  	},
    95  	{"func", func() {}, "<func() Value>", flags{IsCallable: true}},
    96  }
    97  
    98  func TestValue(t *testing.T) {
    99  	for _, lc := range valueCases {
   100  		test := lc
   101  		t.Run(test.name, func(t *testing.T) {
   102  			defer func() {
   103  				if err := recover(); err != nil {
   104  					t.Error(err)
   105  				}
   106  			}()
   107  			assert := assert.New(t)
   108  
   109  			value := exec.AsValue(test.value)
   110  
   111  			assert.Equal(test.asString, value.String())
   112  			test.flags.assert(t, value)
   113  		})
   114  	}
   115  }
   116  
   117  func TestValueFromMap(t *testing.T) {
   118  	for _, lc := range valueCases {
   119  		test := lc
   120  		t.Run(test.name, func(t *testing.T) {
   121  			defer func() {
   122  				if err := recover(); err != nil {
   123  					t.Error(err)
   124  				}
   125  			}()
   126  			assert := assert.New(t)
   127  
   128  			data := map[string]interface{}{"value": test.value}
   129  			value := exec.AsValue(data["value"])
   130  
   131  			assert.Equal(test.asString, value.String())
   132  			test.flags.assert(t, value)
   133  		})
   134  	}
   135  }
   136  
   137  type testStruct struct {
   138  	Attr string
   139  }
   140  
   141  func (t testStruct) String() string {
   142  	return t.Attr
   143  }
   144  
   145  var getattrCases = []struct {
   146  	name     string
   147  	value    interface{}
   148  	attr     string
   149  	found    bool
   150  	asString string
   151  	flags    flags
   152  }{
   153  	{"nil", nil, "missing", false, "", flags{IsError: true}},
   154  	{"attr found", testStruct{"test"}, "Attr", true, "test", flags{IsString: true, IsTrue: true, IsIterable: true}},
   155  	{"attr not found", testStruct{"test"}, "Missing", false, "", flags{IsNil: true}},
   156  	{"item", map[string]interface{}{"Attr": "test"}, "Attr", false, "", flags{IsNil: true}},
   157  }
   158  
   159  func TestValueGetAttr(t *testing.T) {
   160  	for _, lc := range getattrCases {
   161  		test := lc
   162  		t.Run(test.name, func(t *testing.T) {
   163  			defer func() {
   164  				if err := recover(); err != nil {
   165  					t.Error(err)
   166  				}
   167  			}()
   168  			assert := assert.New(t)
   169  
   170  			value := exec.AsValue(test.value)
   171  			out, found := value.Getattr(test.attr)
   172  
   173  			if !test.flags.IsError && out.IsError() {
   174  				t.Fatalf(`Unexpected error: %s`, out.Error())
   175  			}
   176  
   177  			if test.found {
   178  				assert.Truef(found, `Attribute '%s' should be found on %s`, test.attr, value)
   179  				assert.Equal(test.asString, out.String())
   180  			} else {
   181  				assert.Falsef(found, `Attribute '%s' should not be found on %s`, test.attr, value)
   182  			}
   183  
   184  			test.flags.assert(t, out)
   185  		})
   186  	}
   187  }
   188  
   189  var getitemCases = []struct {
   190  	name     string
   191  	value    interface{}
   192  	key      interface{}
   193  	found    bool
   194  	asString string
   195  	flags    flags
   196  }{
   197  	{"nil", nil, "missing", false, "", flags{IsError: true}},
   198  	{"item found", map[string]interface{}{"Attr": "test"}, "Attr", true, "test", flags{IsString: true, IsTrue: true, IsIterable: true}},
   199  	{"item not found", map[string]interface{}{"Attr": "test"}, "Missing", false, "test", flags{IsNil: true}},
   200  	{"attr", testStruct{"test"}, "Attr", false, "", flags{IsNil: true}},
   201  	{"dict found", &exec.Dict{[]*exec.Pair{
   202  		{exec.AsValue("key"), exec.AsValue("value")},
   203  		{exec.AsValue("otherKey"), exec.AsValue("otherValue")},
   204  	}}, "key", true, "value", flags{IsTrue: true, IsString: true, IsIterable: true}},
   205  }
   206  
   207  func TestValueGetitem(t *testing.T) {
   208  	for _, lc := range getitemCases {
   209  		test := lc
   210  		t.Run(test.name, func(t *testing.T) {
   211  			defer func() {
   212  				if err := recover(); err != nil {
   213  					t.Error(err)
   214  				}
   215  			}()
   216  			assert := assert.New(t)
   217  
   218  			value := exec.AsValue(test.value)
   219  			out, found := value.Getitem(test.key)
   220  
   221  			if !test.flags.IsError && out.IsError() {
   222  				t.Fatalf(`Unexpected error: %s`, out.Error())
   223  			}
   224  
   225  			if test.found {
   226  				assert.Truef(found, `Key '%s' should be found on %s`, test.key, value)
   227  				assert.Equal(test.asString, out.String())
   228  			} else {
   229  				assert.Falsef(found, `Key '%s' should not be found on %s`, test.key, value)
   230  			}
   231  
   232  			test.flags.assert(t, out)
   233  		})
   234  	}
   235  }
   236  
   237  var setCases = []struct {
   238  	name     string
   239  	value    interface{}
   240  	attr     string
   241  	set      interface{}
   242  	error    bool
   243  	asString string
   244  }{
   245  	{"nil", nil, "missing", "whatever", true, ""},
   246  	{"existing attr on struct by ref", &testStruct{"test"}, "Attr", "value", false, "value"},
   247  	{"existing attr on struct by value", testStruct{"test"}, "Attr", "value", true, `Can't write field "Attr"`},
   248  	{"missing attr on struct by ref", &testStruct{"test"}, "Missing", "value", true, "test"},
   249  	{"missing attr on struct by value", testStruct{"test"}, "Missing", "value", true, "test"},
   250  	{
   251  		"existing key on map",
   252  		map[string]interface{}{"Attr": "test"},
   253  		"Attr",
   254  		"value",
   255  		false,
   256  		"{'Attr': 'value'}",
   257  	},
   258  	{
   259  		"new key on map",
   260  		map[string]interface{}{"Attr": "test"},
   261  		"New",
   262  		"value",
   263  		false,
   264  		"{'Attr': 'test', 'New': 'value'}",
   265  	},
   266  }
   267  
   268  func TestValueSet(t *testing.T) {
   269  	for _, lc := range setCases {
   270  		test := lc
   271  		t.Run(test.name, func(t *testing.T) {
   272  			defer func() {
   273  				if err := recover(); err != nil {
   274  					t.Error(err)
   275  				}
   276  			}()
   277  			assert := assert.New(t)
   278  
   279  			value := exec.AsValue(test.value)
   280  			err := value.Set(test.attr, test.set)
   281  
   282  			if test.error {
   283  				assert.NotNil(err)
   284  			} else {
   285  				assert.Nil(err)
   286  				assert.Equal(test.asString, value.String())
   287  			}
   288  		})
   289  	}
   290  }
   291  
   292  var valueKeysCases = []struct {
   293  	name     string
   294  	value    interface{}
   295  	asString string
   296  	isError  bool
   297  }{
   298  	{"nil", nil, "", true},
   299  	{"string", "Hello World", "", true},
   300  	{"int", 42, "", true},
   301  	{"float", 42., "", true},
   302  	{"true", true, "", true},
   303  	{"false", false, "", true},
   304  	{"slice", []int{1, 2, 3}, "", true},
   305  	// Map keys are sorted alphabetically, case insensitive
   306  	{"dict as map", map[string]string{"c": "c", "a": "a", "B": "B"}, "['a', 'B', 'c']", false},
   307  	// Dict as Pairs keys are kept in order
   308  	{
   309  		"dict as Dict/Pairs",
   310  		&exec.Dict{[]*exec.Pair{
   311  			{exec.AsValue("c"), exec.AsValue("c")},
   312  			{exec.AsValue("A"), exec.AsValue("A")},
   313  			{exec.AsValue("b"), exec.AsValue("b")},
   314  		}},
   315  		"['c', 'A', 'b']",
   316  		false,
   317  	},
   318  	{"func", func() {}, "", true},
   319  }
   320  
   321  func TestValueKeys(t *testing.T) {
   322  	for _, lc := range valueKeysCases {
   323  		test := lc
   324  		t.Run(test.name, func(t *testing.T) {
   325  			defer func() {
   326  				if err := recover(); err != nil {
   327  					t.Error(err)
   328  				}
   329  			}()
   330  			assert := assert.New(t)
   331  
   332  			value := exec.AsValue(test.value)
   333  			keys := value.Keys()
   334  			if test.isError {
   335  				assert.Len(keys, 0)
   336  			} else {
   337  				assert.Equal(test.asString, keys.String())
   338  			}
   339  		})
   340  	}
   341  }
   342  

View as plain text