| // 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] |
| }`, |
| }, |
| }) |
| } |