tengo_test.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package tengo_test
  2. import (
  3. "strings"
  4. "testing"
  5. "time"
  6. "github.com/d5/tengo/v2"
  7. "github.com/d5/tengo/v2/parser"
  8. "github.com/d5/tengo/v2/require"
  9. )
  10. func TestInstructions_String(t *testing.T) {
  11. assertInstructionString(t,
  12. [][]byte{
  13. tengo.MakeInstruction(parser.OpConstant, 1),
  14. tengo.MakeInstruction(parser.OpConstant, 2),
  15. tengo.MakeInstruction(parser.OpConstant, 65535),
  16. },
  17. `0000 CONST 1
  18. 0003 CONST 2
  19. 0006 CONST 65535`)
  20. assertInstructionString(t,
  21. [][]byte{
  22. tengo.MakeInstruction(parser.OpBinaryOp, 11),
  23. tengo.MakeInstruction(parser.OpConstant, 2),
  24. tengo.MakeInstruction(parser.OpConstant, 65535),
  25. },
  26. `0000 BINARYOP 11
  27. 0002 CONST 2
  28. 0005 CONST 65535`)
  29. assertInstructionString(t,
  30. [][]byte{
  31. tengo.MakeInstruction(parser.OpBinaryOp, 11),
  32. tengo.MakeInstruction(parser.OpGetLocal, 1),
  33. tengo.MakeInstruction(parser.OpConstant, 2),
  34. tengo.MakeInstruction(parser.OpConstant, 65535),
  35. },
  36. `0000 BINARYOP 11
  37. 0002 GETL 1
  38. 0004 CONST 2
  39. 0007 CONST 65535`)
  40. }
  41. func TestMakeInstruction(t *testing.T) {
  42. makeInstruction(t, []byte{parser.OpConstant, 0, 0},
  43. parser.OpConstant, 0)
  44. makeInstruction(t, []byte{parser.OpConstant, 0, 1},
  45. parser.OpConstant, 1)
  46. makeInstruction(t, []byte{parser.OpConstant, 255, 254},
  47. parser.OpConstant, 65534)
  48. makeInstruction(t, []byte{parser.OpPop}, parser.OpPop)
  49. makeInstruction(t, []byte{parser.OpTrue}, parser.OpTrue)
  50. makeInstruction(t, []byte{parser.OpFalse}, parser.OpFalse)
  51. }
  52. func TestNumObjects(t *testing.T) {
  53. testCountObjects(t, &tengo.Array{}, 1)
  54. testCountObjects(t, &tengo.Array{Value: []tengo.Object{
  55. &tengo.Int{Value: 1},
  56. &tengo.Int{Value: 2},
  57. &tengo.Array{Value: []tengo.Object{
  58. &tengo.Int{Value: 3},
  59. &tengo.Int{Value: 4},
  60. &tengo.Int{Value: 5},
  61. }},
  62. }}, 7)
  63. testCountObjects(t, tengo.TrueValue, 1)
  64. testCountObjects(t, tengo.FalseValue, 1)
  65. testCountObjects(t, &tengo.BuiltinFunction{}, 1)
  66. testCountObjects(t, &tengo.Bytes{Value: []byte("foobar")}, 1)
  67. testCountObjects(t, &tengo.Char{Value: '가'}, 1)
  68. testCountObjects(t, &tengo.CompiledFunction{}, 1)
  69. testCountObjects(t, &tengo.Error{Value: &tengo.Int{Value: 5}}, 2)
  70. testCountObjects(t, &tengo.Float{Value: 19.84}, 1)
  71. testCountObjects(t, &tengo.ImmutableArray{Value: []tengo.Object{
  72. &tengo.Int{Value: 1},
  73. &tengo.Int{Value: 2},
  74. &tengo.ImmutableArray{Value: []tengo.Object{
  75. &tengo.Int{Value: 3},
  76. &tengo.Int{Value: 4},
  77. &tengo.Int{Value: 5},
  78. }},
  79. }}, 7)
  80. testCountObjects(t, &tengo.ImmutableMap{
  81. Value: map[string]tengo.Object{
  82. "k1": &tengo.Int{Value: 1},
  83. "k2": &tengo.Int{Value: 2},
  84. "k3": &tengo.Array{Value: []tengo.Object{
  85. &tengo.Int{Value: 3},
  86. &tengo.Int{Value: 4},
  87. &tengo.Int{Value: 5},
  88. }},
  89. }}, 7)
  90. testCountObjects(t, &tengo.Int{Value: 1984}, 1)
  91. testCountObjects(t, &tengo.Map{Value: map[string]tengo.Object{
  92. "k1": &tengo.Int{Value: 1},
  93. "k2": &tengo.Int{Value: 2},
  94. "k3": &tengo.Array{Value: []tengo.Object{
  95. &tengo.Int{Value: 3},
  96. &tengo.Int{Value: 4},
  97. &tengo.Int{Value: 5},
  98. }},
  99. }}, 7)
  100. testCountObjects(t, &tengo.String{Value: "foo bar"}, 1)
  101. testCountObjects(t, &tengo.Time{Value: time.Now()}, 1)
  102. testCountObjects(t, tengo.UndefinedValue, 1)
  103. }
  104. func testCountObjects(t *testing.T, o tengo.Object, expected int) {
  105. require.Equal(t, expected, tengo.CountObjects(o))
  106. }
  107. func assertInstructionString(
  108. t *testing.T,
  109. instructions [][]byte,
  110. expected string,
  111. ) {
  112. concatted := make([]byte, 0)
  113. for _, e := range instructions {
  114. concatted = append(concatted, e...)
  115. }
  116. require.Equal(t, expected, strings.Join(
  117. tengo.FormatInstructions(concatted, 0), "\n"))
  118. }
  119. func makeInstruction(
  120. t *testing.T,
  121. expected []byte,
  122. opcode parser.Opcode,
  123. operands ...int,
  124. ) {
  125. inst := tengo.MakeInstruction(opcode, operands...)
  126. require.Equal(t, expected, inst)
  127. }