| 1 | // Test for issue #26777: assert with || and && should properly short-circuit |
| 2 | module main |
| 3 | |
| 4 | struct Node { |
| 5 | name string |
| 6 | mut: |
| 7 | parent &Node = unsafe { nil } |
| 8 | children []Node |
| 9 | } |
| 10 | |
| 11 | fn test_assert_or_short_circuit_with_nil_parent() { |
| 12 | mut p := Node{ |
| 13 | name: 'abc' |
| 14 | } |
| 15 | // This should work - the right side of || should not be evaluated |
| 16 | // when the left side is true (p.parent == nil) |
| 17 | assert unsafe { p.parent == nil } || !p.parent.children.any(it.name == p.name) |
| 18 | assert true |
| 19 | } |
| 20 | |
| 21 | fn test_assert_and_short_circuit_with_nil_parent() { |
| 22 | mut p := Node{ |
| 23 | name: 'abc' |
| 24 | } |
| 25 | // Test &&: when left is true, right should be evaluated (non-short-circuit path) |
| 26 | // This tests that the right side IS evaluated when left is true |
| 27 | assert true && p.name == 'abc' |
| 28 | // Test && short-circuit: left is false, right should NOT be evaluated |
| 29 | // With fix, right is short-circuited (no nil access) |
| 30 | // Without fix, would crash with nil pointer access |
| 31 | // We use a simple bool expr to avoid assert failure |
| 32 | _ = false && unsafe { p.parent == nil } |
| 33 | } |
| 34 | |
| 35 | fn test_assert_or_with_message() { |
| 36 | mut p := Node{ |
| 37 | name: 'abc' |
| 38 | } |
| 39 | // This should work with a message too |
| 40 | assert unsafe { p.parent == nil } || !p.parent.children.any(it.name == p.name), 'parent check failed' |
| 41 | assert true |
| 42 | } |
| 43 | |
| 44 | fn test_assert_or_both_sides_need_eval() { |
| 45 | mut child := Node{ |
| 46 | name: 'child' |
| 47 | } |
| 48 | // child.parent is nil by default |
| 49 | // Left side is false (child.parent == nil, so child.parent != nil is false) |
| 50 | // Right side must be evaluated - use a simple true to test both sides are evaluated |
| 51 | assert unsafe { child.parent != nil } || true, 'should evaluate both sides' |
| 52 | } |
| 53 | |
| 54 | fn test_nested_or_in_assert() { |
| 55 | mut p := Node{ |
| 56 | name: 'test' |
| 57 | } |
| 58 | // Nested unsafe block with || |
| 59 | assert unsafe { p.parent == nil } || unsafe { p.parent != nil } |
| 60 | assert true |
| 61 | } |
| 62 | |
| 63 | fn main() { |
| 64 | test_assert_or_short_circuit_with_nil_parent() |
| 65 | test_assert_and_short_circuit_with_nil_parent() |
| 66 | test_assert_or_with_message() |
| 67 | test_assert_or_both_sides_need_eval() |
| 68 | test_nested_or_in_assert() |
| 69 | println('All short-circuit tests passed!') |
| 70 | } |
| 71 | |