Coverage Report

Created: 2025-09-05 15:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/noah/src/ruchy/src/testing/generators.rs
Line
Count
Source
1
//! Property-based test generators for AST nodes
2
3
use crate::frontend::ast::{BinaryOp, Expr, ExprKind, Literal, Pattern, Span, UnaryOp};
4
use proptest::prelude::*;
5
use proptest::strategy::{BoxedStrategy, Strategy};
6
7
/// Maximum depth for recursive AST generation to avoid stack overflow
8
const MAX_DEPTH: u32 = 5;
9
10
/// Generate arbitrary literals
11
9.33k
pub fn arb_literal() -> BoxedStrategy<Literal> {
12
9.33k
    prop_oneof![
13
9.33k
        (0i64..i64::MAX).prop_map(Literal::Integer),
14
9.33k
        any::<f64>().prop_map(Literal::Float),
15
9.33k
        any::<bool>().prop_map(Literal::Bool),
16
9.33k
        ".*".prop_map(|s: String| Literal::String(
s.chars()15
.
take15
(20).
collect15
())),
17
9.33k
        Just(Literal::Unit),
18
    ]
19
9.33k
    .boxed()
20
9.33k
}
21
22
/// Generate arbitrary identifiers
23
9.33k
pub fn arb_identifier() -> BoxedStrategy<String> {
24
9.33k
    "[a-z][a-z0-9_]{0,10}".prop_map(|s| s).boxed()
25
9.33k
}
26
27
/// Generate arbitrary binary operators
28
1.55k
pub fn arb_binary_op() -> BoxedStrategy<BinaryOp> {
29
1.55k
    prop_oneof![
30
1.55k
        Just(BinaryOp::Add),
31
1.55k
        Just(BinaryOp::Subtract),
32
1.55k
        Just(BinaryOp::Multiply),
33
1.55k
        Just(BinaryOp::Divide),
34
1.55k
        Just(BinaryOp::Modulo),
35
1.55k
        Just(BinaryOp::Power),
36
1.55k
        Just(BinaryOp::Equal),
37
1.55k
        Just(BinaryOp::NotEqual),
38
1.55k
        Just(BinaryOp::Less),
39
1.55k
        Just(BinaryOp::LessEqual),
40
1.55k
        Just(BinaryOp::Greater),
41
1.55k
        Just(BinaryOp::GreaterEqual),
42
1.55k
        Just(BinaryOp::And),
43
1.55k
        Just(BinaryOp::Or),
44
1.55k
        Just(BinaryOp::BitwiseAnd),
45
1.55k
        Just(BinaryOp::BitwiseOr),
46
1.55k
        Just(BinaryOp::BitwiseXor),
47
1.55k
        Just(BinaryOp::LeftShift),
48
    ]
49
1.55k
    .boxed()
50
1.55k
}
51
52
/// Generate arbitrary unary operators
53
1.55k
pub fn arb_unary_op() -> BoxedStrategy<UnaryOp> {
54
1.55k
    prop_oneof![
55
1.55k
        Just(UnaryOp::Negate),
56
1.55k
        Just(UnaryOp::Not),
57
1.55k
        Just(UnaryOp::BitwiseNot),
58
1.55k
        Just(UnaryOp::Reference),
59
    ]
60
1.55k
    .boxed()
61
1.55k
}
62
63
/// Generate arbitrary expressions with depth limiting
64
9.33k
pub fn arb_expr_with_depth(depth: u32) -> BoxedStrategy<Expr> {
65
9.33k
    if depth >= MAX_DEPTH {
66
        // Base case: only generate non-recursive expressions
67
7.77k
        prop_oneof![
68
7.77k
            arb_literal().prop_map(|lit| 
Expr::new23
(
ExprKind::Literal(lit)23
,
Span::new23
(0, 0))),
69
7.77k
            arb_identifier().prop_map(|id| 
Expr::new24
(
ExprKind::Identifier(id)24
,
Span::new24
(0, 0))),
70
        ]
71
7.77k
        .boxed()
72
    } else {
73
        // Recursive case
74
1.55k
        prop_oneof![
75
            // Literals
76
1.55k
            arb_literal().prop_map(|lit| 
Expr::new36
(
ExprKind::Literal(lit)36
,
Span::new36
(0, 0))),
77
            // Identifiers
78
1.55k
            arb_identifier().prop_map(|id| 
Expr::new45
(
ExprKind::Identifier(id)45
,
Span::new45
(0, 0))),
79
            // Binary operations
80
1.55k
            (
81
1.55k
                arb_expr_with_depth(depth + 1),
82
1.55k
                arb_binary_op(),
83
1.55k
                arb_expr_with_depth(depth + 1),
84
1.55k
            )
85
1.55k
                .prop_map(|(left, op, right)| 
{41
86
41
                    Expr::new(
87
41
                        ExprKind::Binary {
88
41
                            left: Box::new(left),
89
41
                            op,
90
41
                            right: Box::new(right),
91
41
                        },
92
41
                        Span::new(0, 0),
93
                    )
94
41
                }),
95
            // Unary operations
96
1.55k
            (arb_unary_op(), arb_expr_with_depth(depth + 1)).prop_map(|(op, operand)| 
{42
97
42
                Expr::new(
98
42
                    ExprKind::Unary {
99
42
                        op,
100
42
                        operand: Box::new(operand),
101
42
                    },
102
42
                    Span::new(0, 0),
103
                )
104
42
            }),
105
            // If expressions
106
1.55k
            (
107
1.55k
                arb_expr_with_depth(depth + 1),
108
1.55k
                arb_expr_with_depth(depth + 1),
109
1.55k
                prop::option::of(arb_expr_with_depth(depth + 1)),
110
1.55k
            )
111
1.55k
                .prop_map(|(condition, then_branch, else_branch)| 
{39
112
39
                    Expr::new(
113
39
                        ExprKind::If {
114
39
                            condition: Box::new(condition),
115
39
                            then_branch: Box::new(then_branch),
116
39
                            else_branch: else_branch.map(Box::new),
117
39
                        },
118
39
                        Span::new(0, 0),
119
                    )
120
39
                }),
121
        ]
122
1.55k
        .boxed()
123
    }
124
9.33k
}
125
126
/// Generate arbitrary expressions
127
1
pub fn arb_expr() -> BoxedStrategy<Expr> {
128
1
    arb_expr_with_depth(0)
129
1
}
130
131
/// Generate arbitrary patterns
132
0
pub fn arb_pattern() -> BoxedStrategy<Pattern> {
133
0
    prop_oneof![
134
0
        any::<i64>().prop_map(|i| Pattern::Literal(Literal::Integer(i))),
135
0
        any::<bool>().prop_map(|b| Pattern::Literal(Literal::Bool(b))),
136
0
        arb_identifier().prop_map(Pattern::Identifier),
137
0
        Just(Pattern::Wildcard),
138
    ]
139
0
    .boxed()
140
0
}
141
142
/// Generate well-typed expressions (simplified for testing)
143
2
pub fn arb_well_typed_expr() -> BoxedStrategy<Expr> {
144
    // For now, just use simple expressions that are likely to be well-typed
145
2
    prop_oneof![
146
19
        
arb_literal2
().
prop_map2
(|lit| Expr::new(ExprKind::Literal(lit), Span::new(0, 0))),
147
23
        
arb_identifier2
().
prop_map2
(|id| Expr::new(ExprKind::Identifier(id), Span::new(0, 0))),
148
        // Simple arithmetic that's always valid
149
24
        
(any::<i64>(), any::<i64>())2
.
prop_map2
(|(a, b)| {
150
24
            Expr::new(
151
24
                ExprKind::Binary {
152
24
                    left: Box::new(Expr::new(
153
24
                        ExprKind::Literal(Literal::Integer(a)),
154
24
                        Span::new(0, 0),
155
24
                    )),
156
24
                    op: BinaryOp::Add,
157
24
                    right: Box::new(Expr::new(
158
24
                        ExprKind::Literal(Literal::Integer(b)),
159
24
                        Span::new(0, 0),
160
24
                    )),
161
24
                },
162
24
                Span::new(0, 0),
163
            )
164
24
        }),
165
    ]
166
2
    .boxed()
167
2
}