mirror of
https://github.com/allaunthefox/SilverSight.git
synced 2026-07-31 01:25:21 +00:00
- floorDiv returns int64 instead of int32 to match avmClamp signature - instr.Arg wrapped in int64() for avmClamp/avmQ0Clamp calls - Test expected value cast to int32 fix(julia): add Q16_SCALE export to Q16_16 module
112 lines
3.2 KiB
Go
112 lines
3.2 KiB
Go
package avm
|
|
|
|
import "testing"
|
|
|
|
func q16(x int32) Val { return Val{Ty: Q16_16, Q: avmClamp(int64(x))} }
|
|
|
|
func runTest(prog []Instr, fuel int) (*State, error) {
|
|
return Run(NewState(0), prog, fuel)
|
|
}
|
|
|
|
func TestBasicAdd(t *testing.T) {
|
|
prog := []Instr{
|
|
{Op: PushQ16, Arg: 5 * Q16Scale},
|
|
{Op: PushQ16, Arg: 3 * Q16Scale},
|
|
{Op: Primitive, Arg: int32(AddSatQ16)},
|
|
{Op: Halt},
|
|
}
|
|
s, err := runTest(prog, 100)
|
|
if err != nil { t.Fatal(err) }
|
|
if s.Stack[0].Q != 8*Q16Scale { t.Fatalf("got %d", s.Stack[0].Q) }
|
|
}
|
|
|
|
func TestFloorDiv(t *testing.T) {
|
|
// (3 * Q16) / (5 * Q16) = floor(0.6) = 0.6 in Q16
|
|
prog := []Instr{
|
|
{Op: PushQ16, Arg: 3 * Q16Scale},
|
|
{Op: PushQ16, Arg: 5 * Q16Scale},
|
|
{Op: Primitive, Arg: int32(DivSatQ16)},
|
|
{Op: Halt},
|
|
}
|
|
s, err := runTest(prog, 100)
|
|
if err != nil { t.Fatal(err) }
|
|
expected := int32((3 * Q16Scale) / 5)
|
|
if s.Stack[0].Q != expected { t.Fatalf("got %d, expected %d", s.Stack[0].Q, expected) }
|
|
}
|
|
|
|
func TestSaturation(t *testing.T) {
|
|
prog := []Instr{
|
|
{Op: PushQ16, Arg: AVMClampMax - 1},
|
|
{Op: PushQ16, Arg: 2},
|
|
{Op: Primitive, Arg: int32(AddSatQ16)},
|
|
{Op: Halt},
|
|
}
|
|
s, err := runTest(prog, 100)
|
|
if err != nil { t.Fatal(err) }
|
|
if s.Stack[0].Q != AVMClampMax { t.Fatalf("got %d", s.Stack[0].Q) }
|
|
}
|
|
|
|
func TestV6LtQ16(t *testing.T) {
|
|
cases := []struct{ a, b int32; exp bool }{
|
|
{-5 * Q16Scale, -3 * Q16Scale, true},
|
|
{-3 * Q16Scale, -5 * Q16Scale, false},
|
|
{5 * Q16Scale, 3 * Q16Scale, false},
|
|
{3 * Q16Scale, 5 * Q16Scale, true},
|
|
{-1 * Q16Scale, 2 * Q16Scale, true},
|
|
}
|
|
for _, c := range cases {
|
|
prog := []Instr{
|
|
{Op: PushQ16, Arg: c.a},
|
|
{Op: PushQ16, Arg: c.b},
|
|
{Op: Primitive, Arg: int32(LtQ16)},
|
|
{Op: Halt},
|
|
}
|
|
s, err := runTest(prog, 100)
|
|
if err != nil { t.Fatal(err) }
|
|
if s.Stack[0].Bval != c.exp { t.Fatalf("ltQ16(%d,%d): got %v", c.a, c.b, s.Stack[0]) }
|
|
}
|
|
}
|
|
|
|
func TestDivByZero(t *testing.T) {
|
|
prog := []Instr{
|
|
{Op: PushQ16, Arg: Q16Scale},
|
|
{Op: PushQ16, Arg: 0},
|
|
{Op: Primitive, Arg: int32(DivSatQ16)},
|
|
}
|
|
_, err := runTest(prog, 100)
|
|
if err == nil { t.Fatal("expected error") }
|
|
}
|
|
|
|
func TestStackOverflow(t *testing.T) {
|
|
prog := make([]Instr, AVMMaxStack+1)
|
|
for i := range prog { prog[i] = Instr{Op: PushQ16, Arg: 0} }
|
|
_, err := runTest(prog, 10000)
|
|
if err == nil { t.Fatal("expected overflow") }
|
|
}
|
|
|
|
func TestControlFlow(t *testing.T) {
|
|
prog := []Instr{
|
|
{Op: PushBool, Arg2: true},
|
|
{Op: JumpIf, Arg: 4},
|
|
{Op: PushQ16, Arg: 0},
|
|
{Op: Halt},
|
|
{Op: PushQ16, Arg: Q16Scale},
|
|
{Op: Halt},
|
|
}
|
|
s, err := runTest(prog, 100)
|
|
if err != nil { t.Fatal(err) }
|
|
if s.Stack[0].Q != Q16Scale { t.Fatalf("got %d", s.Stack[0].Q) }
|
|
}
|
|
|
|
func TestLocals(t *testing.T) {
|
|
s := NewState(1)
|
|
prog := []Instr{
|
|
{Op: PushQ16, Arg: 42 * Q16Scale},
|
|
{Op: Store, Arg: 0},
|
|
{Op: Load, Arg: 0},
|
|
{Op: Halt},
|
|
}
|
|
result, err := Run(s, prog, 100)
|
|
if err != nil { t.Fatal(err) }
|
|
if result.Stack[0].Q != 42*Q16Scale { t.Fatalf("got %d", result.Stack[0].Q) }
|
|
}
|