neo-go/pkg/compiler/struct_test.go
Evgenii Stratonikov cc5b5bff2e compiler: emit NOTEQUAL only for numbers
Dispatch based on types similarly to EQUAL.
2020-06-11 17:41:52 +03:00

391 lines
4.9 KiB
Go

package compiler_test
import (
"fmt"
"math/big"
"testing"
"github.com/nspcc-dev/neo-go/pkg/vm"
)
var structTestCases = []testCase{
{
"struct field assign",
`
package foo
func Main() int {
t := token {
x: 2,
y: 4,
}
age := t.x
return age
}
type token struct {
x int
y int
}
`,
big.NewInt(2),
},
{
"struct field return",
`
package foo
type token struct {
x int
y int
}
func Main() int {
t := token {
x: 2,
y: 4,
}
return t.x
}
`,
big.NewInt(2),
},
{
"struct field assign",
`
package foo
type token struct {
x int
y int
}
func Main() int {
t := token {
x: 2,
y: 4,
}
t.x = 10
return t.x
}
`,
big.NewInt(10),
},
{
"complex struct",
`
package foo
type token struct {
x int
y int
}
func Main() int {
x := 10
t := token {
x: 2,
y: 4,
}
y := x + t.x
return y
}
`,
big.NewInt(12),
},
{
"initialize struct field from variable",
`
package foo
type token struct {
x int
y int
}
func Main() int {
x := 10
t := token {
x: x,
y: 4,
}
y := t.x + t.y
return y
}`,
big.NewInt(14),
},
{
"assign a variable to a struct field",
`
package foo
type token struct {
x int
y int
}
func Main() int {
ten := 10
t := token {
x: 2,
y: 4,
}
t.x = ten
y := t.y + t.x
return y
}`,
big.NewInt(14),
},
{
"increase struct field with +=",
`package foo
type token struct { x int }
func Main() int {
t := token{x: 2}
t.x += 3
return t.x
}`,
big.NewInt(5),
},
{
"assign a struct field to a struct field",
`
package foo
type token struct {
x int
y int
}
func Main() int {
t1 := token {
x: 2,
y: 4,
}
t2 := token {
x: 3,
y: 5,
}
t1.x = t2.y
y := t1.x + t2.x
return y
}`,
big.NewInt(8),
},
{
"initialize same struct twice",
`
package foo
type token struct {
x int
y int
}
func Main() int {
t1 := token {
x: 2,
y: 4,
}
t2 := token {
x: 2,
y: 4,
}
return t1.x + t2.y
}
`,
big.NewInt(6),
},
{
"struct methods",
`
package foo
type token struct {
x int
}
func(t token) getInteger() int {
return t.x
}
func Main() int {
t := token {
x: 4,
}
someInt := t.getInteger()
return someInt
}
`,
big.NewInt(4),
},
{
"struct methods with arguments",
`
package foo
type token struct {
x int
}
// Also tests if x conflicts with t.x
func(t token) addIntegers(x int, y int) int {
return t.x + x + y
}
func Main() int {
t := token {
x: 4,
}
someInt := t.addIntegers(2, 4)
return someInt
}
`,
big.NewInt(10),
},
{
"initialize struct partially",
`
package foo
type token struct {
x int
y int
z string
b bool
}
func Main() int {
t := token {
x: 4,
}
return t.y
}
`,
[]byte{},
},
{
"test return struct from func",
`
package foo
type token struct {
x int
y int
z string
b bool
}
func newToken() token {
return token{
x: 1,
y: 2,
z: "hello",
b: false,
}
}
func Main() token {
return newToken()
}
`,
[]vm.StackItem{
vm.NewBigIntegerItem(1),
vm.NewBigIntegerItem(2),
vm.NewByteArrayItem([]byte("hello")),
vm.NewByteArrayItem([]byte{}),
},
},
{
"pass struct as argument",
`
package foo
type Bar struct {
amount int
}
func addToAmount(x int, bar Bar) int {
bar.amount = bar.amount + x
return bar.amount
}
func Main() int {
b := Bar{
amount: 10,
}
x := addToAmount(4, b)
return x
}
`,
big.NewInt(14),
},
{
"declare struct literal",
`package foo
func Main() int {
var x struct {
a int
}
x.a = 2
return x.a
}`,
big.NewInt(2),
},
{
"declare struct type",
`package foo
type withA struct {
a int
}
func Main() int {
var x withA
x.a = 2
return x.a
}`,
big.NewInt(2),
},
{
"uninitialized struct fields",
`package foo
type Foo struct {
i int
m map[string]int
b []byte
a []int
s struct { ii int }
}
func NewFoo() Foo { return Foo{} }
func Main() int {
foo := NewFoo()
if foo.i != 0 { return 1 }
if len(foo.m) != 0 { return 1 }
if len(foo.b) != 0 { return 1 }
if len(foo.a) != 0 { return 1 }
s := foo.s
if s.ii != 0 { return 1 }
return 2
}`,
big.NewInt(2),
},
}
func TestStructs(t *testing.T) {
runTestCases(t, structTestCases)
}
func TestStructCompare(t *testing.T) {
srcTmpl := `package testcase
type T struct { f int }
func Main() int {
a := T{f: %d}
b := T{f: %d}
if a != b {
return 2
}
return 1
}`
t.Run("Equal", func(t *testing.T) {
src := fmt.Sprintf(srcTmpl, 4, 4)
eval(t, src, big.NewInt(1))
})
t.Run("NotEqual", func(t *testing.T) {
src := fmt.Sprintf(srcTmpl, 4, 5)
eval(t, src, big.NewInt(2))
})
}