Skip to content

Commit c4683aa

Browse files
Simon SomethingSimon Something
Simon Something
authored and
Simon Something
committed
feat: test bin op
1 parent c0ffeea commit c4683aa

File tree

4 files changed

+225
-0
lines changed

4 files changed

+225
-0
lines changed

crates/forge/src/mutation/mutant.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ impl Display for UnaryOpMutated {
2727
}
2828
}
2929

30+
// @todo add a mutation from universalmutator: line swap (swap two lines of code, as it
31+
// could theoretically uncover untested reentrancies
3032
#[derive(Debug)]
3133
pub enum MutationType {
3234
// @todo Solar doesn't differentiate numeric type in LitKind (only on declaration?) -> for

crates/forge/src/mutation/mutators/tests/ast_helper.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,31 @@ pub fn create_number_lit(value: u32, span: Span) -> Lit {
3232
pub fn create_bool_lit(value: bool, span: Span) -> Lit {
3333
Lit { span, symbol: Symbol::DUMMY, kind: LitKind::Bool(value) }
3434
}
35+
36+
use std::{collections::HashMap, hash::Hash};
37+
38+
pub fn all_but_one<T: Eq + Hash>(theoretic: &[T], observed: &[T]) -> bool {
39+
if theoretic.len() != observed.len() + 1 {
40+
return false;
41+
}
42+
43+
let mut counts = HashMap::new();
44+
45+
for item in theoretic {
46+
*counts.entry(item).or_insert(0) += 1;
47+
}
48+
49+
for item in observed {
50+
if let Some(count) = counts.get_mut(item) {
51+
*count -= 1;
52+
if *count == 0 {
53+
counts.remove(item);
54+
}
55+
} else {
56+
return false; // observed has something not in theoretic
57+
}
58+
}
59+
60+
// Only one item should remain in the map
61+
counts.len() == 1 && counts.values().all(|&v| v == 1)
62+
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
use crate::mutation::{
2+
mutant::{Mutant, MutationType},
3+
mutators::{
4+
binary_op_mutator::BinaryOpMutator, tests::ast_helper::all_but_one, MutationContext,
5+
Mutator,
6+
},
7+
visitor::AssignVarTypes,
8+
Session,
9+
};
10+
use solar_parse::{
11+
ast::{
12+
Arena, BinOp, BinOpKind, ElementaryType, Expr, ExprKind, Ident, Lit, LitKind, Span, Symbol,
13+
Type, TypeKind, VariableDefinition,
14+
},
15+
interface::BytePos,
16+
};
17+
18+
use super::*;
19+
20+
fn create_span(start: u32, end: u32) -> Span {
21+
Span::new(BytePos(start), BytePos(end))
22+
}
23+
24+
#[test]
25+
fn test_is_applicable_for_binary_expr() {
26+
let arena = Arena::new();
27+
let span = create_span(10, 20);
28+
29+
let mut val = Lit { span, symbol: Symbol::DUMMY, kind: LitKind::Number(23.into()) };
30+
let mut val2 = Lit { span, symbol: Symbol::DUMMY, kind: LitKind::Number(45.into()) };
31+
32+
let left = arena.alloc(Expr { kind: ExprKind::Lit(&mut val, None), span });
33+
34+
let right = arena.alloc(Expr { kind: ExprKind::Lit(&mut val2, None), span });
35+
36+
let bin_op = BinOp { span, kind: BinOpKind::Add };
37+
38+
let expr = arena.alloc(Expr { kind: ExprKind::Binary(left, bin_op, right), span });
39+
40+
let context = MutationContext { expr: Some(expr), var_definition: None, span };
41+
42+
let mutator = BinaryOpMutator;
43+
assert!(mutator.is_applicable(&context));
44+
}
45+
46+
#[test]
47+
fn test_is_applicable_for_assign_expr() {
48+
let arena = Arena::new();
49+
let span = create_span(10, 20);
50+
51+
let left =
52+
arena.alloc(Expr { kind: ExprKind::Ident(Ident { name: Symbol::DUMMY, span }), span });
53+
54+
let mut val = Lit { span, symbol: Symbol::DUMMY, kind: LitKind::Number(23.into()) };
55+
56+
let right = arena.alloc(Expr { kind: ExprKind::Lit(&mut val, None), span });
57+
58+
let bin_op = BinOp { span, kind: BinOpKind::Add };
59+
60+
let expr = arena.alloc(Expr { kind: ExprKind::Assign(left, Some(bin_op), right), span });
61+
62+
let context = MutationContext { expr: Some(expr), var_definition: None, span };
63+
64+
let mutator = BinaryOpMutator;
65+
assert!(mutator.is_applicable(&context));
66+
}
67+
68+
#[test]
69+
fn test_is_not_applicable_assign_without_binary_op() {
70+
let arena = Arena::new();
71+
72+
let span = create_span(10, 20);
73+
74+
let left =
75+
arena.alloc(Expr { kind: ExprKind::Ident(Ident { name: Symbol::DUMMY, span }), span });
76+
77+
let mut val = Lit { span, symbol: Symbol::DUMMY, kind: LitKind::Number(23.into()) };
78+
79+
let right = arena.alloc(Expr { kind: ExprKind::Lit(&mut val, None), span });
80+
81+
let expr = arena.alloc(Expr { kind: ExprKind::Assign(left, None, right), span });
82+
83+
let context = MutationContext { expr: Some(expr), var_definition: None, span };
84+
85+
let mutator = BinaryOpMutator;
86+
assert!(!mutator.is_applicable(&context));
87+
}
88+
89+
#[test]
90+
fn test_generate_arithmetic_mutants() {
91+
let arena = Arena::new();
92+
let span = create_span(10, 20);
93+
94+
let sess = Session::builder().with_silent_emitter(None).build();
95+
96+
let _ = sess.enter(|| -> solar_parse::interface::Result<()> {
97+
let mut val = Lit { span, symbol: Symbol::DUMMY, kind: LitKind::Number(23.into()) };
98+
let mut val2 = Lit { span, symbol: Symbol::DUMMY, kind: LitKind::Number(45.into()) };
99+
100+
let left = arena.alloc(Expr { kind: ExprKind::Lit(&mut val, None), span });
101+
102+
let right = arena.alloc(Expr { kind: ExprKind::Lit(&mut val2, None), span });
103+
104+
let bin_op = BinOp { span, kind: BinOpKind::Add };
105+
106+
let expr = arena.alloc(Expr { kind: ExprKind::Binary(left, bin_op, right), span });
107+
108+
let context = MutationContext { expr: Some(expr), var_definition: None, span };
109+
110+
let mutator = BinaryOpMutator;
111+
let mutants = mutator.generate_mutants(&context).unwrap();
112+
113+
let operations_num_bitwise = vec![
114+
// Arithm
115+
BinOpKind::Shr,
116+
BinOpKind::Shl,
117+
BinOpKind::Sar,
118+
BinOpKind::BitAnd,
119+
BinOpKind::BitOr,
120+
BinOpKind::BitXor,
121+
BinOpKind::Add,
122+
BinOpKind::Sub,
123+
BinOpKind::Pow,
124+
BinOpKind::Mul,
125+
BinOpKind::Div,
126+
BinOpKind::Rem,
127+
];
128+
129+
assert_eq!(mutants.len(), operations_num_bitwise.len() - 1);
130+
131+
let mutants_kind = mutants
132+
.iter()
133+
.map(|m| match m.mutation {
134+
MutationType::BinaryOp(kind) => kind,
135+
_ => panic!("Expected binary op mutant"),
136+
})
137+
.collect::<Vec<_>>();
138+
139+
assert!(all_but_one(&operations_num_bitwise, &mutants_kind));
140+
141+
Ok(())
142+
});
143+
}
144+
145+
#[test]
146+
fn test_generate_bool_op_mutants() {
147+
let arena = Arena::new();
148+
let span = create_span(10, 20);
149+
150+
let sess = Session::builder().with_silent_emitter(None).build();
151+
152+
let _ = sess.enter(|| -> solar_parse::interface::Result<()> {
153+
let mut val = Lit { span, symbol: Symbol::DUMMY, kind: LitKind::Number(23.into()) };
154+
let mut val2 = Lit { span, symbol: Symbol::DUMMY, kind: LitKind::Number(45.into()) };
155+
156+
let left = arena.alloc(Expr { kind: ExprKind::Lit(&mut val, None), span });
157+
158+
let right = arena.alloc(Expr { kind: ExprKind::Lit(&mut val2, None), span });
159+
160+
let bin_op = BinOp { span, kind: BinOpKind::Lt };
161+
162+
let expr = arena.alloc(Expr { kind: ExprKind::Binary(left, bin_op, right), span });
163+
164+
let context = MutationContext { expr: Some(expr), var_definition: None, span };
165+
166+
let mutator = BinaryOpMutator;
167+
let mutants = mutator.generate_mutants(&context).unwrap();
168+
169+
let operations_bools = vec![
170+
BinOpKind::Lt,
171+
BinOpKind::Le,
172+
BinOpKind::Gt,
173+
BinOpKind::Ge,
174+
BinOpKind::Eq,
175+
BinOpKind::Ne,
176+
BinOpKind::Or,
177+
BinOpKind::And,
178+
];
179+
180+
assert_eq!(mutants.len(), operations_bools.len() - 1);
181+
182+
let mutants_kind = mutants
183+
.iter()
184+
.map(|m| match m.mutation {
185+
MutationType::BinaryOp(kind) => kind,
186+
_ => panic!("Expected binary op mutant"),
187+
})
188+
.collect::<Vec<_>>();
189+
190+
assert!(all_but_one(&operations_bools, &mutants_kind));
191+
192+
Ok(())
193+
});
194+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
mod assignement_mutator_test;
22
mod ast_helper;
3+
mod binary_op_mutator_test;

0 commit comments

Comments
 (0)