391 lines
5.3 KiB
Go
Executable File
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)
|
|
})
|
|
}
|
|
}
|