// Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package inline_test import "testing" // Testcases mostly come in pairs, of a success and a failure // to substitute based on specific constant argument values. func TestFalconStringIndex(t *testing.T) { runTests(t, []testcase{ { "Non-negative string index.", `func f(i int) byte { return s[i] }; var s string`, `func _() { f(0) }`, `func _() { _ = s[0] }`, }, { "Negative string index.", `func f(i int) byte { return s[i] }; var s string`, `func _() { f(-1) }`, `func _() { var i int = -1 _ = s[i] }`, }, { "String index in range.", `func f(s string, i int) byte { return s[i] }`, `func _() { f("-", 0) }`, `func _() { _ = "-"[0] }`, }, { "String index out of range.", `func f(s string, i int) byte { return s[i] }`, `func _() { f("-", 1) }`, `func _() { var ( s string = "-" i int = 1 ) _ = s[i] }`, }, { "Remove known prefix (OK)", `func f(s, prefix string) string { return s[:len(prefix)] }`, `func _() { f("", "") }`, `func _() { _ = ""[:len("")] }`, }, { "Remove not-a-prefix (out of range)", `func f(s, prefix string) string { return s[:len(prefix)] }`, `func _() { f("", "pre") }`, `func _() { var s, prefix string = "", "pre" _ = s[:len(prefix)] }`, }, }) } func TestFalconSliceIndices(t *testing.T) { runTests(t, []testcase{ { "Monotonic (0<=i<=j) slice indices (len unknown).", `func f(i, j int) []int { return s[i:j] }; var s []int`, `func _() { f(0, 1) }`, `func _() { _ = s[0:1] }`, }, { "Non-monotonic slice indices (len unknown).", `func f(i, j int) []int { return s[i:j] }; var s []int`, `func _() { f(1, 0) }`, `func _() { var i, j int = 1, 0 _ = s[i:j] }`, }, { "Negative slice index.", `func f(i, j int) []int { return s[i:j] }; var s []int`, `func _() { f(-1, 1) }`, `func _() { var i, j int = -1, 1 _ = s[i:j] }`, }, }) } func TestFalconMapKeys(t *testing.T) { runTests(t, []testcase{ { "Unique map keys (int)", `func f(x int) { _ = map[int]bool{1: true, x: true} }`, `func _() { f(2) }`, `func _() { _ = map[int]bool{1: true, 2: true} }`, }, { "Duplicate map keys (int)", `func f(x int) { _ = map[int]bool{1: true, x: true} }`, `func _() { f(1) }`, `func _() { var x int = 1 _ = map[int]bool{1: true, x: true} }`, }, { "Unique map keys (varied built-in types)", `func f(x int16) { _ = map[any]bool{1: true, x: true} }`, `func _() { f(2) }`, `func _() { _ = map[any]bool{1: true, int16(2): true} }`, }, { "Duplicate map keys (varied built-in types)", `func f(x int16) { _ = map[any]bool{1: true, x: true} }`, `func _() { f(1) }`, `func _() { _ = map[any]bool{1: true, int16(1): true} }`, }, { "Unique map keys (varied user-defined types)", `func f(x myint) { _ = map[any]bool{1: true, x: true} }; type myint int`, `func _() { f(2) }`, `func _() { _ = map[any]bool{1: true, myint(2): true} }`, }, { "Duplicate map keys (varied user-defined types)", `func f(x myint, y myint2) { _ = map[any]bool{x: true, y: true} }; type (myint int; myint2 int)`, `func _() { f(1, 1) }`, `func _() { var ( x myint = 1 y myint2 = 1 ) _ = map[any]bool{x: true, y: true} }`, }, { "Duplicate map keys (user-defined alias to built-in)", `func f(x myint, y int) { _ = map[any]bool{x: true, y: true} }; type myint = int`, `func _() { f(1, 1) }`, `func _() { var ( x myint = 1 y int = 1 ) _ = map[any]bool{x: true, y: true} }`, }, }) } func TestFalconSwitchCases(t *testing.T) { runTests(t, []testcase{ { "Unique switch cases (int).", `func f(x int) { switch 0 { case x: case 1: } }`, `func _() { f(2) }`, `func _() { switch 0 { case 2: case 1: } }`, }, { "Duplicate switch cases (int).", `func f(x int) { switch 0 { case x: case 1: } }`, `func _() { f(1) }`, `func _() { var x int = 1 switch 0 { case x: case 1: } }`, }, { "Unique switch cases (varied built-in types).", `func f(x int) { switch any(nil) { case x: case int16(1): } }`, `func _() { f(2) }`, `func _() { switch any(nil) { case 2: case int16(1): } }`, }, { "Duplicate switch cases (varied built-in types).", `func f(x int) { switch any(nil) { case x: case int16(1): } }`, `func _() { f(1) }`, `func _() { switch any(nil) { case 1: case int16(1): } }`, }, }) } func TestFalconDivision(t *testing.T) { runTests(t, []testcase{ { "Division by two.", `func f(x, y int) int { return x / y }`, `func _() { f(1, 2) }`, `func _() { _ = 1 / 2 }`, }, { "Division by zero.", `func f(x, y int) int { return x / y }`, `func _() { f(1, 0) }`, `func _() { var x, y int = 1, 0 _ = x / y }`, }, { "Division by two (statement).", `func f(x, y int) { x /= y }`, `func _() { f(1, 2) }`, `func _() { var x int = 1 x /= 2 }`, }, { "Division by zero (statement).", `func f(x, y int) { x /= y }`, `func _() { f(1, 0) }`, `func _() { var x, y int = 1, 0 x /= y }`, }, { "Division of minint by two (ok).", `func f(x, y int32) { _ = x / y }`, `func _() { f(-0x80000000, 2) }`, `func _() { _ = int32(-0x80000000) / int32(2) }`, }, { "Division of minint by -1 (overflow).", `func f(x, y int32) { _ = x / y }`, `func _() { f(-0x80000000, -1) }`, `func _() { var x, y int32 = -0x80000000, -1 _ = x / y }`, }, }) } func TestFalconMinusMinInt(t *testing.T) { runTests(t, []testcase{ { "Negation of maxint.", `func f(x int32) int32 { return -x }`, `func _() { f(0x7fffffff) }`, `func _() { _ = -int32(0x7fffffff) }`, }, { "Negation of minint.", `func f(x int32) int32 { return -x }`, `func _() { f(-0x80000000) }`, `func _() { var x int32 = -0x80000000 _ = -x }`, }, }) } func TestFalconArithmeticOverflow(t *testing.T) { runTests(t, []testcase{ { "Addition without overflow.", `func f(x, y int32) int32 { return x + y }`, `func _() { f(100, 200) }`, `func _() { _ = int32(100) + int32(200) }`, }, { "Addition with overflow.", `func f(x, y int32) int32 { return x + y }`, `func _() { f(1<<30, 1<<30) }`, `func _() { var x, y int32 = 1 << 30, 1 << 30 _ = x + y }`, }, { "Conversion in range.", `func f(x int) int8 { return int8(x) }`, `func _() { f(123) }`, `func _() { _ = int8(123) }`, }, { "Conversion out of range.", `func f(x int) int8 { return int8(x) }`, `func _() { f(456) }`, `func _() { var x int = 456 _ = int8(x) }`, }, }) } func TestFalconComplex(t *testing.T) { runTests(t, []testcase{ { "Complex arithmetic (good).", `func f(re, im float64, z complex128) byte { return "x"[int(real(complex(re, im)*complex(re, -im)-z))] }`, `func _() { f(1, 2, 5+0i) }`, `func _() { _ = "x"[int(real(complex(1, 2)*complex(1, -2)-(5+0i)))] }`, }, { "Complex arithmetic (bad).", `func f(re, im float64, z complex128) byte { return "x"[int(real(complex(re, im)*complex(re, -im)-z))] }`, `func _() { f(1, 3, 5+0i) }`, `func _() { var ( re, im float64 = 1, 3 z complex128 = 5 + 0i ) _ = "x"[int(real(complex(re, im)*complex(re, -im)-z))] }`, }, }) } func TestFalconMisc(t *testing.T) { runTests(t, []testcase{ { "Compound constant expression (good).", `func f(x, y string, i, j int) byte { return x[i*len(y)+j] }`, `func _() { f("abc", "xy", 2, -3) }`, `func _() { _ = "abc"[2*len("xy")+-3] }`, }, { "Compound constant expression (index out of range).", `func f(x, y string, i, j int) byte { return x[i*len(y)+j] }`, `func _() { f("abc", "xy", 4, -3) }`, `func _() { var ( x, y string = "abc", "xy" i, j int = 4, -3 ) _ = x[i*len(y)+j] }`, }, { "Constraints within nested functions (good).", `func f(x int) { _ = func() { _ = [1]int{}[x] } }`, `func _() { f(0) }`, `func _() { _ = func() { _ = [1]int{}[0] } }`, }, { "Constraints within nested functions (bad).", `func f(x int) { _ = func() { _ = [1]int{}[x] } }`, `func _() { f(1) }`, `func _() { var x int = 1 _ = func() { _ = [1]int{}[x] } }`, }, { "Falcon violation rejects only the constant arguments (x, z).", `func f(x, y, z string) string { return x[:2] + y + z[:2] }; var b string`, `func _() { f("a", b, "c") }`, `func _() { var x, z string = "a", "c" _ = x[:2] + b + z[:2] }`, }, }) }