tutus-chain/pkg/compiler/switch_test.go

391 lines
5.3 KiB
Go
Executable File

package compiler_test
import (
"bytes"
"fmt"
"math/big"
"strings"
"testing"
"git.marketally.com/tutus-one/tutus-chain/pkg/compiler"
"git.marketally.com/tutus-one/tutus-chain/pkg/vm"
"github.com/stretchr/testify/require"
)
var switchTestCases = []testCase{
{
"simple switch success",
`func F%d() int {
a := 5
switch a {
case 5: return 2
}
return 1
}
`,
big.NewInt(2),
},
{
"switch with no tag",
`func f() bool { return false }
func F%d() int {
switch {
case f():
return 1
case true:
return 2
}
return 3
}
`,
big.NewInt(2),
},
{
"type conversion in tag",
`type state int
func F%d() int {
a := 1
switch state(a) {
case 1:
return 42
default:
return 11
}
}
`,
big.NewInt(42),
},
{
"simple switch fail",
`func F%d() int {
a := 6
switch a {
case 5:
return 2
}
return 1
}
`,
big.NewInt(1),
},
{
"multiple cases success",
`func F%d() int {
a := 6
switch a {
case 5: return 2
case 6: return 3
}
return 1
}
`,
big.NewInt(3),
},
{
"multiple cases fail",
`func F%d() int {
a := 7
switch a {
case 5: return 2
case 6: return 3
}
return 1
}
`,
big.NewInt(1),
},
{
"default case",
`func F%d() int {
a := 7
switch a {
case 5: return 2
case 6: return 3
default: return 4
}
return 1
}
`,
big.NewInt(4),
},
{
"empty case before default",
`func F%d() int {
a := 6
switch a {
case 5: return 2
case 6:
default: return 4
}
return 1
}
`,
big.NewInt(1),
},
{
"expression in case clause",
`func F%d() int {
a := 6
b := 3
switch a {
case 5: return 2
case b*3-3: return 3
}
return 1
}
`,
big.NewInt(3),
},
{
"multiple expressions in case",
`func F%d() int {
a := 8
b := 3
switch a {
case 5: return 2
case b*3-3, 7, 8: return 3
}
return 1
}
`,
big.NewInt(3),
},
{
"string switch",
`func F%d() int {
name := "Valera"
switch name {
case "Misha": return 2
case "Katya", "Dima": return 3
case "Lera", "Valer" + "a": return 4
}
return 1
}
`,
big.NewInt(4),
},
{
"break from switch",
`func F%d() int {
i := 3
switch i {
case 2: return 2
case 3:
i = 1
break
return 3
case 4: return 4
}
return i
}
`,
big.NewInt(1),
},
{
"break from outer for",
`func F%d() int {
i := 3
loop:
for i < 10 {
i++
switch i {
case 5:
i = 7
break loop
return 3
case 6: return 4
}
}
return i
}
`,
big.NewInt(7),
},
{
"continue outer for",
`func F%d() int {
i := 2
for i < 10 {
i++
switch i {
case 3:
i = 7
continue
case 4, 5, 6, 7: return 5
case 8: return 2
}
if i == 7 {
return 6
}
}
return i
}
`,
big.NewInt(2),
},
{
"simple fallthrough",
`func F%d() int {
n := 2
switch n {
case 1: return 5
case 2: fallthrough
case 3: return 6
}
return 7
}
`,
big.NewInt(6),
},
{
"double fallthrough",
`func F%d() int {
n := 2
k := 5
switch n {
case 0: return k
case 1: fallthrough
case 2:
k++
fallthrough
case 3:
case 4:
k++
return k
}
return k
}
`,
big.NewInt(6),
},
{
"init assignment",
`func F%d() int {
var n int
switch n = 1; {
}
return n
}
`,
big.NewInt(1),
},
{
"init short decl with shadowing",
`func F%d() int {
n := 10
switch n := 1; {
default:
if n != 1 {
return -1
}
}
return n
}
`,
big.NewInt(10),
},
{
"init with multiple assignment",
`func F%d() int {
var a, b int
switch a, b = 2, 3; {
default:
return a+b
}
}
`,
big.NewInt(5),
},
{
"init with multiple assignment, without shadowing",
`func F%d() int {
switch a, b := 2, 3; {
default:
return a+b
}
}
`,
big.NewInt(5),
},
{
"init with function call",
`var g int
func set(v int) int { g = v; return v }
func F%d() int {
g = 0
switch x := set(7); x {
case 7:
return g
default:
return -1
}
}
`,
big.NewInt(7),
},
{
"init evaluation order",
`var order []int
func add(v int) int { order = append(order, v); return v }
func F%d() int {
order = nil
switch add(1); add(2) {
case 2:
if len(order) == 2 && order[0] == 1 && order[1] == 2 {
return 42
}
}
return -1
}
`,
big.NewInt(42),
},
{
"init without tag",
`func F%d() int {
var x int
switch x = 7; {
case x == 7:
return x
default:
return -1
}
}
`,
big.NewInt(7),
},
{
"init short decl with multi shadowing",
`func F%d() int {
a, b := 0, 0
switch a, b := 3, 4; {
default:
return a+b
}
return a+b
}
`,
big.NewInt(7),
},
}
func TestSwitch(t *testing.T) {
srcBuilder := bytes.NewBuffer([]byte("package testcase\n"))
for i, tc := range switchTestCases {
_, err := fmt.Fprintf(srcBuilder, tc.src, i)
require.NoError(t, err)
}
ne, di, err := compiler.CompileWithOptions("file.go", strings.NewReader(srcBuilder.String()), nil)
require.NoError(t, err)
for i, tc := range switchTestCases {
t.Run(tc.name, func(t *testing.T) {
v := vm.New()
invokeMethod(t, fmt.Sprintf("F%d", i), ne.Script, v, di)
runAndCheck(t, v, tc.result)
})
}
}