1use rand::{distributions::uniform::SampleUniform, seq::SliceRandom, Rng};
2use tree_sitter::Node;
3
4use crate::{
5 error::{MutantKrakenError, Result},
6 kotlin_types::{KotlinExceptions, KotlinTypes},
7 mutation_tool::Mutation,
8};
9use std::{
10 collections::{HashMap, HashSet},
11 fmt::Display,
12 fs,
13};
14
15#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
17pub enum MutationOperators {
18 ArithmeticReplacementOperator,
20 UnaryRemovalOperator,
22 LogicalReplacementOperator,
24 RelationalReplacementOperator,
26 AssignmentReplacementOperator,
28 UnaryReplacementOperator,
30 NotNullAssertionOperator,
32 ElvisRemoveOperator,
34 ElvisLiteralChangeOperator,
36 LiteralChangeOperator,
38 ExceptionChangeOperator,
40 WhenRemoveBranchOperator,
42 RemoveLabelOperator,
44 FunctionalBinaryReplacementOperator,
46 FunctionalReplacementOperator,
48}
49
50impl Display for MutationOperators {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 write!(
53 f,
54 "{}",
55 match self {
56 MutationOperators::ArithmeticReplacementOperator => "ArithmeticReplacementOperator",
57 MutationOperators::UnaryRemovalOperator => "UnaryRemovalOperator",
58 MutationOperators::LogicalReplacementOperator => "LogicalReplacementOperator",
59 MutationOperators::RelationalReplacementOperator => "RelationalReplacementOperator",
60 MutationOperators::AssignmentReplacementOperator => "AssignmentReplacementOperator",
61 MutationOperators::UnaryReplacementOperator => "UnaryReplacementOperator",
62 MutationOperators::NotNullAssertionOperator => "NotNullAssertionOperator",
63 MutationOperators::ElvisRemoveOperator => "ElvisRemoveOperator",
64 MutationOperators::ElvisLiteralChangeOperator => "ElvisLiteralChangeOperator",
65 MutationOperators::LiteralChangeOperator => "LiteralChangeOperator",
66 MutationOperators::ExceptionChangeOperator => "ExceptionChangeOperator",
67 MutationOperators::WhenRemoveBranchOperator => "WhenRemoveBranchOperator",
68 MutationOperators::RemoveLabelOperator => "RemoveLabelOperator",
69 MutationOperators::FunctionalBinaryReplacementOperator => {
70 "FunctionalBinaryReplacementOperator"
71 }
72 MutationOperators::FunctionalReplacementOperator => "FunctionalReplacementOperator",
73 }
74 )
75 }
76}
77
78impl MutationOperators {
79 fn get_operators(&self) -> HashSet<KotlinTypes> {
81 match self {
82 MutationOperators::ArithmeticReplacementOperator => vec![
83 KotlinTypes::NonNamedType("+".to_string()),
84 KotlinTypes::NonNamedType("-".to_string()),
85 KotlinTypes::NonNamedType("*".to_string()),
86 KotlinTypes::NonNamedType("/".to_string()),
87 KotlinTypes::NonNamedType("%".to_string()),
88 ]
89 .into_iter()
90 .collect(),
91 MutationOperators::UnaryRemovalOperator => vec![
92 KotlinTypes::NonNamedType("+".to_string()),
93 KotlinTypes::NonNamedType("-".to_string()),
94 KotlinTypes::NonNamedType("!".to_string()),
95 ]
96 .into_iter()
97 .collect(),
98 MutationOperators::LogicalReplacementOperator => vec![
99 KotlinTypes::NonNamedType("&&".to_string()),
100 KotlinTypes::NonNamedType("||".to_string()),
101 ]
102 .into_iter()
103 .collect(),
104 MutationOperators::RelationalReplacementOperator => vec![
105 KotlinTypes::NonNamedType("==".to_string()),
106 KotlinTypes::NonNamedType("!=".to_string()),
107 KotlinTypes::NonNamedType("<".to_string()),
108 KotlinTypes::NonNamedType("<=".to_string()),
109 KotlinTypes::NonNamedType(">".to_string()),
110 KotlinTypes::NonNamedType(">=".to_string()),
111 ]
112 .into_iter()
113 .collect(),
114 MutationOperators::AssignmentReplacementOperator => vec![
115 KotlinTypes::NonNamedType("=".to_string()),
116 KotlinTypes::NonNamedType("+=".to_string()),
117 KotlinTypes::NonNamedType("-=".to_string()),
118 KotlinTypes::NonNamedType("*=".to_string()),
119 KotlinTypes::NonNamedType("/=".to_string()),
120 KotlinTypes::NonNamedType("%=".to_string()),
121 ]
122 .into_iter()
123 .collect(),
124 MutationOperators::UnaryReplacementOperator => vec![
125 KotlinTypes::NonNamedType("!".to_string()),
126 KotlinTypes::NonNamedType("++".to_string()),
127 KotlinTypes::NonNamedType("--".to_string()),
128 KotlinTypes::RemoveOperator,
129 ]
130 .into_iter()
131 .collect(),
132 MutationOperators::NotNullAssertionOperator => vec![
133 KotlinTypes::NonNamedType("!!".to_string()),
134 KotlinTypes::NonNamedType("?.".to_string()),
135 KotlinTypes::RemoveOperator,
136 ]
137 .into_iter()
138 .collect(),
139 MutationOperators::ElvisRemoveOperator
140 | MutationOperators::ElvisLiteralChangeOperator => {
141 vec![KotlinTypes::NonNamedType("?:".to_string())]
142 .into_iter()
143 .collect()
144 }
145 MutationOperators::LiteralChangeOperator => vec![
146 KotlinTypes::IntegerLiteral,
147 KotlinTypes::StringLiteral,
148 KotlinTypes::BooleanLiteral,
149 KotlinTypes::LongLiteral,
150 KotlinTypes::RealLiteral,
151 KotlinTypes::CharacterLiteral,
152 ]
153 .into_iter()
154 .collect(),
155 MutationOperators::ExceptionChangeOperator => {
156 vec![KotlinTypes::NonNamedType("throw".to_string())]
157 .into_iter()
158 .collect()
159 }
160 MutationOperators::WhenRemoveBranchOperator => {
161 vec![KotlinTypes::WhenExpression].into_iter().collect()
162 }
163 MutationOperators::RemoveLabelOperator => {
164 vec![KotlinTypes::JumpExpression].into_iter().collect()
165 }
166 MutationOperators::FunctionalBinaryReplacementOperator
167 | MutationOperators::FunctionalReplacementOperator => {
168 vec![KotlinTypes::SimpleIdentifier].into_iter().collect()
169 }
170 }
171 }
172
173 fn get_parent_necessary_types(&self) -> Vec<KotlinTypes> {
175 match self {
176 MutationOperators::ArithmeticReplacementOperator => vec![
177 KotlinTypes::AdditiveExpression,
178 KotlinTypes::MultiplicativeExpression,
179 ],
180 MutationOperators::UnaryRemovalOperator => vec![KotlinTypes::PrefixExpression],
181 MutationOperators::LogicalReplacementOperator => vec![
182 KotlinTypes::ConjunctionExpression,
183 KotlinTypes::DisjunctionExpression,
184 ],
185 MutationOperators::RelationalReplacementOperator => vec![
186 KotlinTypes::EqualityExpression,
187 KotlinTypes::ComparisonExpression,
188 ],
189 MutationOperators::AssignmentReplacementOperator => vec![KotlinTypes::Assignment],
190 MutationOperators::UnaryReplacementOperator => vec![
191 KotlinTypes::PostfixExpression,
192 KotlinTypes::PrefixExpression,
193 ],
194 MutationOperators::NotNullAssertionOperator => vec![KotlinTypes::PostfixExpression],
195 MutationOperators::ElvisRemoveOperator
196 | MutationOperators::ElvisLiteralChangeOperator => {
197 vec![KotlinTypes::ElvisExpression]
198 }
199 MutationOperators::LiteralChangeOperator => vec![
200 KotlinTypes::IntegerLiteral,
201 KotlinTypes::StringLiteral,
202 KotlinTypes::BooleanLiteral,
203 KotlinTypes::LongLiteral,
204 KotlinTypes::RealLiteral,
205 KotlinTypes::CharacterLiteral,
206 KotlinTypes::PrefixExpression,
207 KotlinTypes::PostfixExpression,
208 KotlinTypes::AdditiveExpression,
209 KotlinTypes::MultiplicativeExpression,
210 KotlinTypes::ConjunctionExpression,
211 KotlinTypes::DisjunctionExpression,
212 KotlinTypes::EqualityExpression,
213 KotlinTypes::ComparisonExpression,
214 KotlinTypes::PropertyDeclaration,
215 KotlinTypes::VariableDeclaration,
216 ],
217 MutationOperators::ExceptionChangeOperator => {
218 vec![KotlinTypes::JumpExpression]
219 }
220 MutationOperators::WhenRemoveBranchOperator
221 | MutationOperators::RemoveLabelOperator => vec![KotlinTypes::AnyParent],
222 MutationOperators::FunctionalBinaryReplacementOperator
223 | MutationOperators::FunctionalReplacementOperator => {
224 vec![KotlinTypes::NavigationSuffix]
225 }
226 }
227 }
228
229 pub fn find_mutation(&self, ast: &tree_sitter::Tree, file_name: &String) -> Vec<Mutation> {
231 let mut mutations = Vec::new();
232 let mut cursor = ast.walk();
233 let root = ast.root_node();
234 self.mutate(root, &mut cursor, None, &mut mutations, file_name);
235 mutations
236 }
237 fn mutate(
248 &self,
249 root: tree_sitter::Node,
250 cursor: &mut tree_sitter::TreeCursor,
251 parent: Option<tree_sitter::Node>,
252 mutations_made: &mut Vec<Mutation>,
253 file_name: &String,
254 ) {
255 root.children(&mut cursor.clone()).for_each(|node| {
256 let root_type = KotlinTypes::new(node.kind())
257 .expect(format!("Failed to convert to KotlinType: {:?}", node.kind()).as_str());
258 let parent_type = parent
259 .map(|p| KotlinTypes::new(p.kind()).expect("Failed to convert to KotlinType"));
260 mutations_made.append(
261 &mut self
262 .mutate_operator(&node, &root_type, &parent_type, file_name)
263 .expect("Failed to mutate an operator"),
264 );
265 self.mutate(node, cursor, Some(node), mutations_made, file_name);
266 });
267 }
268
269 fn mutate_operator(
284 &self,
285 root_node: &tree_sitter::Node,
286 root: &KotlinTypes,
287 parent: &Option<KotlinTypes>,
288 file_name: &str,
289 ) -> Result<Vec<Mutation>> {
290 let mut mutations_made = Vec::new();
291 let mutation_operators = self.get_operators();
292 let parent_types = self.get_parent_necessary_types();
293 if !mutation_operators.contains(root)
297 || parent.is_none()
298 || (!parent_types.contains(&KotlinTypes::AnyParent)
299 && !parent_types
300 .contains(parent.as_ref().ok_or(MutantKrakenError::ConversionError)?))
301 {
302 return Ok(mutations_made);
303 }
304
305 match *self {
306 MutationOperators::UnaryRemovalOperator => {
307 let mutation = Mutation::new(
309 root_node.start_byte(),
310 root_node.end_byte(),
311 KotlinTypes::RemoveOperator.to_string(),
312 root.as_str(),
313 root_node.start_position().row + 1,
314 self.clone(),
315 file_name.to_string(),
316 );
317 mutations_made.push(mutation);
318 }
319 MutationOperators::ElvisRemoveOperator => {
320 let end_byte = root_node.parent().unwrap().end_byte(); let mutation = Mutation::new(
325 root_node.start_byte(),
326 end_byte,
327 KotlinTypes::RemoveOperator.to_string(),
328 root.as_str(),
329 root_node.start_position().row + 1,
330 self.clone(),
331 file_name.to_string(),
332 );
333 mutations_made.push(mutation);
334 }
335 MutationOperators::ElvisLiteralChangeOperator
336 | MutationOperators::LiteralChangeOperator => {
337 self.mutate_literal(&root_node.parent().unwrap(), &mut mutations_made, file_name)
338 }
339 MutationOperators::ExceptionChangeOperator => {
340 self.mutate_exception(root_node, &mut mutations_made, file_name)
341 }
342 MutationOperators::WhenRemoveBranchOperator => {
343 self.mutate_when(root_node, &mut mutations_made, file_name)
344 }
345 MutationOperators::RemoveLabelOperator => {
346 self.mutate_label(root_node, &mut mutations_made, file_name)
347 }
348 MutationOperators::FunctionalBinaryReplacementOperator => {
349 self.mutate_functional_binary(root_node, &mut mutations_made, file_name)
350 }
351 MutationOperators::FunctionalReplacementOperator => {
352 self.mutate_functional(root_node, &mut mutations_made, file_name)
353 }
354 _ => {
355 mutation_operators.iter().for_each(|operator| {
357 if operator != root {
358 let mutation = Mutation::new(
359 root_node.start_byte(),
360 root_node.end_byte(),
361 operator.to_string(),
362 root.as_str(),
363 root_node.start_position().row + 1,
364 self.clone(),
365 file_name.to_string(),
366 );
367 mutations_made.push(mutation)
368 }
369 });
370 }
371 }
372
373 Ok(mutations_made)
374 }
375
376 fn mutate_functional(
377 &self,
378 root_node: &tree_sitter::Node,
379 mutations_made: &mut Vec<Mutation>,
380 file_name: &str,
381 ) {
382 let predicates = ["any", "all", "none"];
383 let transform = ["forEach", "map", "filter"];
384
385 let file = fs::read(file_name).expect("Failed to read file");
388 let file = file.as_slice();
389 let val = root_node.utf8_text(file).unwrap();
390
391 if !predicates.contains(&val) && !transform.contains(&val) {
392 return;
393 }
394
395 let mut rng = rand::thread_rng();
397 let mut mut_val = val;
398 let type_val = if predicates.contains(&val) {
399 "predicate"
400 } else {
401 "transform"
402 };
403 while mut_val == val {
404 mut_val = match type_val {
405 "predicate" => predicates.choose(&mut rng).unwrap(),
406 "transform" => transform.choose(&mut rng).unwrap(),
407 _ => panic!("Invalid type"),
408 };
409 }
410
411 let mutation = Mutation::new(
412 root_node.start_byte(),
413 root_node.end_byte(),
414 mut_val.into(),
415 val.to_string(),
416 root_node.start_position().row + 1,
417 self.clone(),
418 file_name.to_string(),
419 );
420 mutations_made.push(mutation);
421 }
422
423 fn mutate_functional_binary(
424 &self,
425 root_node: &tree_sitter::Node,
426 mutations_made: &mut Vec<Mutation>,
427 file_name: &str,
428 ) {
429 let changes = HashMap::from([
430 ("first", "last"),
431 ("last", "first"),
432 ("firstOrNull", "lastOrNull"),
433 ("lastOrNull", "firstOrNull"),
434 ("find", "findLast"),
435 ("findLast", "find"),
436 ]);
437
438 let file = fs::read(file_name).expect("Failed to read file");
441 let file = file.as_slice();
442 let val = root_node.utf8_text(file).unwrap();
443
444 if !changes.contains_key(val) {
445 return;
446 }
447
448 let mut_val = changes[val];
449
450 let mutation = Mutation::new(
451 root_node.start_byte(),
452 root_node.end_byte(),
453 mut_val.into(),
454 val.to_string(),
455 root_node.start_position().row + 1,
456 self.clone(),
457 file_name.to_string(),
458 );
459 mutations_made.push(mutation);
460 }
461
462 fn mutate_label(
463 &self,
464 root_node: &tree_sitter::Node,
465 mutations_made: &mut Vec<Mutation>,
466 file_name: &str,
467 ) {
468 let file = fs::read(file_name).expect("Failed to read file");
470 let file = file.as_slice();
471 let val = root_node.utf8_text(file).unwrap();
472
473 if !val.contains('@')
475 && (!val.starts_with("return")
476 || !val.starts_with("continue")
477 || !val.starts_with("break"))
478 {
479 return;
480 }
481
482 let label_start = val.find('@').unwrap();
484 let mut_value = val[0..label_start].to_string();
485
486 let mutation = Mutation::new(
487 root_node.start_byte(),
488 root_node.end_byte(),
489 mut_value,
490 val.to_string(),
491 root_node.start_position().row + 1,
492 self.clone(),
493 file_name.to_string(),
494 );
495
496 mutations_made.push(mutation);
497 }
498
499 fn mutate_when(
500 &self,
501 root_node: &tree_sitter::Node,
502 mutations_made: &mut Vec<Mutation>,
503 file_name: &str,
504 ) {
505 let when_entry_list = root_node
507 .children(&mut root_node.walk())
508 .filter_map(|node| {
509 let kt_node =
510 KotlinTypes::new(node.kind()).expect("Failed to convert to KotlinType");
511 if kt_node == KotlinTypes::WhenEntry {
512 Some(node)
513 } else {
514 None
515 }
516 })
517 .collect::<Vec<Node<'_>>>();
518
519 if when_entry_list.len() < 2 {
521 return;
522 }
523
524 let mut rng = rand::thread_rng();
526 let index = rng.gen_range(0..when_entry_list.len() - 1);
527 let node = when_entry_list.get(index).unwrap();
528
529 let mutation = Mutation::new(
531 node.start_byte(),
532 node.end_byte(),
533 KotlinTypes::RemoveOperator.to_string(),
534 "When Branch".to_string(),
535 node.start_position().row + 1,
536 self.clone(),
537 file_name.to_string(),
538 );
539
540 mutations_made.push(mutation);
541 }
542
543 fn mutate_exception(
544 &self,
545 root_node: &tree_sitter::Node,
546 mutations_made: &mut Vec<Mutation>,
547 file_name: &str,
548 ) {
549 let sibling = root_node.next_sibling().unwrap();
551 let sibling_type =
552 KotlinTypes::new(sibling.kind()).expect("Failed to convert to KotlinType");
553 if sibling_type != KotlinTypes::CallExpression {
555 return;
556 }
557
558 let child = sibling.children(&mut sibling.walk()).next().unwrap();
559 let child_type = KotlinTypes::new(child.kind()).expect("Failed to convert to KotlinType");
560 if child_type != KotlinTypes::SimpleIdentifier {
562 return;
563 }
564 let file = fs::read(file_name).expect("Failed to read file");
566 let file = file.as_slice();
567 let val = child.utf8_text(file).unwrap();
568 let exception: KotlinExceptions = val
569 .parse()
570 .unwrap_or(KotlinExceptions::ArithmArithmeticException);
571
572 let mut_val = exception.get_random_exception().to_string();
574
575 let mutation = Mutation::new(
576 child.start_byte(),
577 child.end_byte(),
578 mut_val,
579 val.to_string(),
580 child.start_position().row + 1,
581 self.clone(),
582 file_name.to_string(),
583 );
584
585 mutations_made.push(mutation);
586 }
587
588 fn mutate_literal(
589 &self,
590 root_node: &tree_sitter::Node,
591 mutations_made: &mut Vec<Mutation>,
592 file_name: &str,
593 ) {
594 let file = fs::read(file_name).expect("Failed to read file");
595 let file = file.as_slice();
596 let children = root_node
597 .children(&mut root_node.walk())
598 .collect::<Vec<tree_sitter::Node>>();
599 let node = match children.iter().last() {
600 Some(node) => node,
601 None => root_node,
602 };
603
604 let child_type = KotlinTypes::new(node.kind())
605 .expect(format!("Failed to convert to KotlinType: {:?}", node.kind()).as_str());
606 let mut val = node.utf8_text(file).unwrap();
608 match child_type {
609 KotlinTypes::IntegerLiteral => {
610 let val = val.replace('_', "").parse::<i32>();
611 if val.is_err() {
612 return;
613 }
614 let val = val.unwrap();
615 let mutated_val = generate_random_literal(val, i32::MIN, i32::MAX);
617 let mutation = Mutation::new(
618 node.start_byte(),
619 node.end_byte(),
620 mutated_val.to_string(),
621 val.to_string(),
622 node.start_position().row + 1,
623 self.clone(),
624 file_name.to_string(),
625 );
626 mutations_made.push(mutation);
627 }
628 KotlinTypes::PrefixExpression => {
629 self.mutate_literal(node, mutations_made, file_name)
632 }
633 KotlinTypes::StringLiteral => {
634 let val = r#""Hello I am a Mutant!""#.to_string();
636
637 let mutation = Mutation::new(
638 node.start_byte(),
639 node.end_byte(),
640 val,
641 node.utf8_text(file).unwrap().to_string(),
642 node.start_position().row + 1,
643 self.clone(),
644 file_name.to_string(),
645 );
646 mutations_made.push(mutation);
647 }
648 KotlinTypes::BooleanLiteral => {
649 let val = val.parse::<bool>().unwrap();
650 let mutated_val = !val;
652
653 let mutation = Mutation::new(
654 node.start_byte(),
655 node.end_byte(),
656 mutated_val.to_string(),
657 val.to_string(),
658 node.start_position().row + 1,
659 self.clone(),
660 file_name.to_string(),
661 );
662 mutations_made.push(mutation);
663 }
664 KotlinTypes::LongLiteral => {
665 if val.ends_with('L') {
667 val = val.strip_suffix('L').unwrap();
668 }
669
670 let val = val.replace('_', "").parse::<i64>();
671 if val.is_err() {
672 return;
673 }
674 let val = val.unwrap();
675 let mutated_val = generate_random_literal(val, i64::MIN, i64::MAX);
677
678 let mutation = Mutation::new(
679 node.start_byte(),
680 node.end_byte(),
681 mutated_val.to_string(),
682 val.to_string(),
683 node.start_position().row + 1,
684 self.clone(),
685 file_name.to_string(),
686 );
687 mutations_made.push(mutation);
688 }
689 KotlinTypes::RealLiteral => {
690 if val.ends_with('f') {
692 val = val.strip_suffix('f').unwrap();
693 }
694 let val = val.parse::<f32>();
695 if val.is_err() {
696 return;
697 }
698 let val = val.unwrap();
699 let mutated_val = generate_random_literal(val, 0.0, 1.0);
701 let mutation = Mutation::new(
702 node.start_byte(),
703 node.end_byte(),
704 mutated_val.to_string(),
705 val.to_string(),
706 node.start_position().row + 1,
707 self.clone(),
708 file_name.to_string(),
709 );
710
711 mutations_made.push(mutation);
712 }
713 KotlinTypes::CharacterLiteral => {
714 let val = val
716 .strip_prefix('\'')
717 .unwrap()
718 .strip_suffix('\'')
719 .unwrap()
720 .chars()
721 .next()
722 .unwrap();
723
724 let mut rnd_val = rand::thread_rng().gen_range(b'a'..=b'z') as char;
726 while rnd_val == val {
727 rnd_val = rand::thread_rng().gen_range(b'a'..=b'z') as char;
728 }
729 let mut_val = format!("'{}'", rnd_val);
730 let mutation = Mutation::new(
731 node.start_byte(),
732 node.end_byte(),
733 mut_val,
734 val.to_string(),
735 node.start_position().row + 1,
736 self.clone(),
737 file_name.to_string(),
738 );
739 mutations_made.push(mutation);
740 }
741 _ => {}
742 }
743 }
744}
745
746fn generate_random_literal<T>(original_literal: T, min: T, max: T) -> T
747where
748 T: std::cmp::PartialOrd + std::cmp::PartialEq + Copy + SampleUniform,
749{
750 let mut rng = rand::thread_rng();
751
752 let mut random_literal = rng.gen_range(min..max);
754
755 while random_literal == original_literal {
757 random_literal = rng.gen_range(min..max);
758 }
759
760 random_literal
761}
762
763#[cfg(test)]
764mod tests {
765 use std::{env::temp_dir, io::Write};
766
767 use crate::mutation_tool::test_util::*;
768
769 use super::*;
770 use crate::mutation_tool::debug_print_ast;
771 use tree_sitter::Parser;
772
773 fn get_ast(text: &str) -> tree_sitter::Tree {
774 let mut parser = Parser::new();
775 parser
776 .set_language(&tree_sitter_kotlin::language())
777 .expect("Failed to set language for parser");
778 parser.parse(text, None).expect("Failed to parse text")
779 }
780
781 #[test]
782 fn test_arthimetic_operator() {
783 let tree = get_ast(KOTLIN_TEST_CODE);
784 let root = tree.root_node();
785 let mut mutations_made = Vec::new();
786 MutationOperators::ArithmeticReplacementOperator.mutate(
787 root,
788 &mut root.walk(),
789 None,
790 &mut mutations_made,
791 &"".into(),
792 );
793 dbg!(&mutations_made);
794 assert_eq!(mutations_made.len(), 20);
795 for mutation in mutations_made {
796 assert_ne!(mutation.old_op, mutation.new_op);
797 }
798 }
799
800 #[test]
801 fn test_relational_operator() {
802 let tree = get_ast(KOTLIN_RELATIONAL_TEST_CODE);
803 let root = tree.root_node();
804 let mut mutations_made = Vec::new();
805 MutationOperators::RelationalReplacementOperator.mutate(
806 root,
807 &mut root.walk(),
808 None,
809 &mut mutations_made,
810 &"".into(),
811 );
812
813 assert_eq!(mutations_made.len(), 30);
814 for mutation in mutations_made {
816 assert_ne!(mutation.old_op, mutation.new_op);
817 }
818 }
819
820 #[test]
821 fn test_logical_operator() {
822 let tree = get_ast(KOTLIN_LOGICAL_TEST_CODE);
823 let root = tree.root_node();
824 let mut mutations_made = Vec::new();
825 MutationOperators::LogicalReplacementOperator.mutate(
826 root,
827 &mut root.walk(),
828 None,
829 &mut mutations_made,
830 &"".into(),
831 );
832 dbg!(&mutations_made);
833 assert_eq!(mutations_made.len(), 2);
834 for mutation in mutations_made {
836 assert_ne!(mutation.old_op, mutation.new_op);
837 }
838 }
839
840 #[test]
841 fn test_assignment_operator() {
842 let tree = get_ast(KOTLIN_ASSIGNMENT_TEST_CODE);
843 let root = tree.root_node();
844 let mut mutations_made = Vec::new();
845 MutationOperators::AssignmentReplacementOperator.mutate(
846 root,
847 &mut root.walk(),
848 None,
849 &mut mutations_made,
850 &"".into(),
851 );
852 dbg!(&mutations_made);
853 assert_eq!(mutations_made.len(), 25);
854 for mutation in mutations_made {
856 assert_ne!(mutation.old_op, mutation.new_op);
857 }
858 }
859
860 #[test]
861 fn test_unary_operator() {
862 let tree = get_ast(KOTLIN_UNARY_TEST_CODE);
863 let root = tree.root_node();
864 let mut mutations_made = Vec::new();
865 MutationOperators::UnaryReplacementOperator.mutate(
866 root,
867 &mut root.walk(),
868 None,
869 &mut mutations_made,
870 &"".into(),
871 );
872 dbg!(&mutations_made);
873 assert_eq!(mutations_made.len(), 12);
874 for mutation in mutations_made {
876 assert_ne!(mutation.old_op, mutation.new_op);
877 }
878 }
879
880 #[test]
881 fn test_unary_removal_operator() {
882 let tree = get_ast(KOTLIN_UNARY_REMOVAL_TEST_CODE);
883 let root = tree.root_node();
884 let mut mutations_made = Vec::new();
885 MutationOperators::UnaryRemovalOperator.mutate(
886 root,
887 &mut root.walk(),
888 None,
889 &mut mutations_made,
890 &"".into(),
891 );
892 dbg!(&mutations_made);
893 assert_eq!(mutations_made.len(), 3);
894 for mutation in mutations_made {
896 assert_ne!(mutation.old_op, mutation.new_op);
897 assert_eq!(mutation.new_op, "RemoveOperator".to_string());
898 }
899 }
900
901 #[test]
902 fn test_not_null_assetion_operator() {
903 let tree = get_ast(KOTLIN_TEST_NULL_ASSERTION_CODE);
904 let root = tree.root_node();
905 let mut mutations_made = Vec::new();
906 MutationOperators::NotNullAssertionOperator.mutate(
907 root,
908 &mut root.walk(),
909 None,
910 &mut mutations_made,
911 &"".into(),
912 );
913 dbg!(&mutations_made);
914 assert_eq!(mutations_made.len(), 2);
915 for mutation in mutations_made {
917 assert_ne!(mutation.old_op, mutation.new_op);
918 }
919 }
920
921 #[test]
922 fn test_elvis_remove_operator() {
923 let tree = get_ast(KOTLIN_ELVIS_TEST_CODE);
924 let root = tree.root_node();
925 let mut mutations_made = Vec::new();
926 MutationOperators::ElvisRemoveOperator.mutate(
927 root,
928 &mut root.walk(),
929 None,
930 &mut mutations_made,
931 &"".into(),
932 );
933 assert_eq!(mutations_made.len(), 1);
934 for mutation in mutations_made {
936 assert_ne!(mutation.old_op, mutation.new_op);
937 assert_eq!(mutation.new_op, "RemoveOperator".to_string());
938 }
939 }
940
941 #[test]
942 fn test_elvis_literal_operator() {
943 let temp_dir = temp_dir();
945 let temp_file = temp_dir.join("temp_file.kt");
946 let mut file = fs::File::create(&temp_file).expect("Failed to create temp file");
947 file.write_all(KOTLIN_ELVIS_LITERAL_TEST_CODE.as_bytes())
948 .expect("Failed to write to temp file");
949
950 let tree = get_ast(KOTLIN_ELVIS_LITERAL_TEST_CODE);
951
952 let root = tree.root_node();
953 let mut mutations_made = Vec::new();
954 MutationOperators::ElvisLiteralChangeOperator.mutate(
955 root,
956 &mut root.walk(),
957 None,
958 &mut mutations_made,
959 &temp_file.to_str().unwrap().to_string(),
960 );
961 assert_eq!(mutations_made.len(), 12);
962 for mutation in mutations_made {
964 assert_ne!(mutation.old_op, mutation.new_op);
965 }
966 }
967
968 #[test]
969 fn test_literal_change_operator() {
970 let temp_dir = temp_dir();
972 let temp_file = temp_dir.join("literal_change_temp_file.kt");
973 let mut file = fs::File::create(&temp_file).expect("Failed to create temp file");
974 file.write_all(KOTLIN_LITERAL_TEST_CODE.as_bytes())
975 .expect("Failed to write to temp file");
976 let tree = get_ast(KOTLIN_LITERAL_TEST_CODE);
977 let root = tree.root_node();
978 debug_print_ast(&root, 0);
979 let mut mutations_made = Vec::new();
980 MutationOperators::LiteralChangeOperator.mutate(
981 root,
982 &mut root.walk(),
983 None,
984 &mut mutations_made,
985 &temp_file.to_str().unwrap().to_string(),
986 );
987 assert_eq!(mutations_made.len(), 12);
988 for mutation in mutations_made {
990 assert_ne!(mutation.old_op, mutation.new_op);
991 }
992 }
993
994 #[test]
995 fn test_exception_change_operator() {
996 let temp_dir = temp_dir();
998 let temp_file = temp_dir.join("exception_change_temp_file.kt");
999 let mut file = fs::File::create(&temp_file).expect("Failed to create temp file");
1000 file.write_all(KOTLIN_EXCEPTION_TEST_CODE.as_bytes())
1001 .expect("Failed to write to temp file");
1002 let tree = get_ast(KOTLIN_EXCEPTION_TEST_CODE);
1003 let root = tree.root_node();
1004 debug_print_ast(&root, 0);
1005 let mut mutations_made = Vec::new();
1006 MutationOperators::ExceptionChangeOperator.mutate(
1007 root,
1008 &mut root.walk(),
1009 None,
1010 &mut mutations_made,
1011 &temp_file.to_str().unwrap().to_string(),
1012 );
1013 assert_eq!(mutations_made.len(), 3);
1014 for mutation in mutations_made {
1016 assert_ne!(mutation.old_op, mutation.new_op);
1017 }
1018 }
1019
1020 #[test]
1021 fn test_when_remove_branch_operator() {
1022 let temp_dir = temp_dir();
1024 let temp_file = temp_dir.join("when_remove_branch_temp_file.kt");
1025 let mut file = fs::File::create(&temp_file).expect("Failed to create temp file");
1026 file.write_all(KOTLIN_WHEN_EXPRESSION_TEST_CODE.as_bytes())
1027 .expect("Failed to write to temp file");
1028 let tree = get_ast(KOTLIN_WHEN_EXPRESSION_TEST_CODE);
1029 let root = tree.root_node();
1030 debug_print_ast(&root, 0);
1031 let mut mutations_made = Vec::new();
1032 MutationOperators::WhenRemoveBranchOperator.mutate(
1033 root,
1034 &mut root.walk(),
1035 None,
1036 &mut mutations_made,
1037 &temp_file.to_str().unwrap().to_string(),
1038 );
1039 assert_eq!(mutations_made.len(), 2);
1040 }
1041
1042 #[test]
1043 fn test_label_remove_operator() {
1044 let temp_dir = temp_dir();
1046 let temp_file = temp_dir.join("label_remove_temp_file.kt");
1047 let mut file = fs::File::create(&temp_file).expect("Failed to create temp file");
1048 file.write_all(KOTLIN_LABEL_REMOVING_TEST_CODE.as_bytes())
1049 .expect("Failed to write to temp file");
1050 let tree = get_ast(KOTLIN_LABEL_REMOVING_TEST_CODE);
1051 let root = tree.root_node();
1052 debug_print_ast(&root, 0);
1053 let mut mutations_made = Vec::new();
1054 MutationOperators::RemoveLabelOperator.mutate(
1055 root,
1056 &mut root.walk(),
1057 None,
1058 &mut mutations_made,
1059 &temp_file.to_str().unwrap().to_string(),
1060 );
1061 assert_eq!(mutations_made.len(), 3);
1062 }
1063
1064 #[test]
1065 fn test_functional_binary_replacement_operator() {
1066 let temp_dir = temp_dir();
1068 let temp_file = temp_dir.join("functional_find_find_last_temp_file.kt");
1069 let mut file = fs::File::create(&temp_file).expect("Failed to create temp file");
1070 file.write_all(KOTLIN_FUNCTIONAL_BINARY_REPLACEMENT_CODE.as_bytes())
1071 .expect("Failed to write to temp file");
1072 let tree = get_ast(KOTLIN_FUNCTIONAL_BINARY_REPLACEMENT_CODE);
1073 let root = tree.root_node();
1074 debug_print_ast(&root, 0);
1075 let mut mutations_made = Vec::new();
1076 MutationOperators::FunctionalBinaryReplacementOperator.mutate(
1077 root,
1078 &mut root.walk(),
1079 None,
1080 &mut mutations_made,
1081 &temp_file.to_str().unwrap().to_string(),
1082 );
1083 assert_eq!(mutations_made.len(), 6);
1084 }
1085
1086 #[test]
1087 fn test_functional_replacement_operator() {
1088 let temp_dir = temp_dir();
1090 let temp_file = temp_dir.join("functional_any_all_none_temp_file.kt");
1091 let mut file = fs::File::create(&temp_file).expect("Failed to create temp file");
1092 file.write_all(KOTLIN_FUNCTIONAL_REPLACEMENT_CODE.as_bytes())
1093 .expect("Failed to write to temp file");
1094 let tree = get_ast(KOTLIN_FUNCTIONAL_REPLACEMENT_CODE);
1095 let root = tree.root_node();
1096 debug_print_ast(&root, 0);
1097 let mut mutations_made = Vec::new();
1098 MutationOperators::FunctionalReplacementOperator.mutate(
1099 root,
1100 &mut root.walk(),
1101 None,
1102 &mut mutations_made,
1103 &temp_file.to_str().unwrap().to_string(),
1104 );
1105 assert_eq!(mutations_made.len(), 6);
1106 }
1107
1108 #[test]
1109 fn test_arthimetic_operator_does_not_create_mutations() {
1110 let tree = get_ast(KOTLIN_UNARY_REMOVAL_TEST_CODE);
1111 let root = tree.root_node();
1112 let mut mutations_made = Vec::new();
1113 MutationOperators::ArithmeticReplacementOperator.mutate(
1114 root,
1115 &mut root.walk(),
1116 None,
1117 &mut mutations_made,
1118 &"".into(),
1119 );
1120 assert_eq!(mutations_made.len(), 0);
1121 }
1122
1123 #[test]
1124 fn test_relational_operator_does_not_create_mutations() {
1125 let tree = get_ast(KOTLIN_UNARY_REMOVAL_TEST_CODE);
1126 let root = tree.root_node();
1127 let mut mutations_made = Vec::new();
1128 MutationOperators::RelationalReplacementOperator.mutate(
1129 root,
1130 &mut root.walk(),
1131 None,
1132 &mut mutations_made,
1133 &"".into(),
1134 );
1135 assert_eq!(mutations_made.len(), 0);
1136 }
1137
1138 #[test]
1139 fn test_logical_operator_does_not_create_mutations() {
1140 let tree = get_ast(KOTLIN_UNARY_REMOVAL_TEST_CODE);
1141 let root = tree.root_node();
1142 let mut mutations_made = Vec::new();
1143 MutationOperators::LogicalReplacementOperator.mutate(
1144 root,
1145 &mut root.walk(),
1146 None,
1147 &mut mutations_made,
1148 &"".into(),
1149 );
1150 assert_eq!(mutations_made.len(), 0);
1151 }
1152
1153 #[test]
1154 fn test_assignment_operator_does_not_create_mutations() {
1155 let tree = get_ast(KOTLIN_UNARY_REMOVAL_TEST_CODE);
1156 let root = tree.root_node();
1157 let mut mutations_made = Vec::new();
1158 MutationOperators::AssignmentReplacementOperator.mutate(
1159 root,
1160 &mut root.walk(),
1161 None,
1162 &mut mutations_made,
1163 &"".into(),
1164 );
1165 assert_eq!(mutations_made.len(), 0);
1166 }
1167
1168 #[test]
1169 fn test_when_remove_operator_does_not_create_mutations() {
1170 let tree = get_ast(KOTLIN_UNARY_REMOVAL_TEST_CODE);
1171 let root = tree.root_node();
1172 let mut mutations_made = Vec::new();
1173 MutationOperators::WhenRemoveBranchOperator.mutate(
1174 root,
1175 &mut root.walk(),
1176 None,
1177 &mut mutations_made,
1178 &"".into(),
1179 );
1180 assert_eq!(mutations_made.len(), 0);
1181 }
1182
1183 #[test]
1184 fn test_unary_removal_operator_does_not_create_mutations() {
1185 let tree = get_ast(KOTLIN_ASSIGNMENT_TEST_CODE);
1186 let mutations_made =
1187 MutationOperators::UnaryRemovalOperator.find_mutation(&tree, &"file_name".into());
1188 assert_eq!(mutations_made.len(), 0);
1189 }
1190
1191 #[test]
1192 fn test_unary_replacement_operator_does_not_create_mutations() {
1193 let tree = get_ast(KOTLIN_ASSIGNMENT_TEST_CODE);
1194 let mutations_made =
1195 MutationOperators::UnaryReplacementOperator.find_mutation(&tree, &"file_name".into());
1196 assert_eq!(mutations_made.len(), 0);
1197 }
1198
1199 #[test]
1200 fn test_not_null_assertion_operator_does_not_create_mutations() {
1201 let tree = get_ast(KOTLIN_ASSIGNMENT_TEST_CODE);
1202 let mutations_made =
1203 MutationOperators::NotNullAssertionOperator.find_mutation(&tree, &"file_name".into());
1204 assert_eq!(mutations_made.len(), 0);
1205 }
1206
1207 #[test]
1208 fn test_remove_elvis_operator_does_not_create_mutations() {
1209 let tree = get_ast(KOTLIN_UNARY_REMOVAL_TEST_CODE);
1210 let root = tree.root_node();
1211 let mut mutations_made = Vec::new();
1212 MutationOperators::ElvisRemoveOperator.mutate(
1213 root,
1214 &mut root.walk(),
1215 None,
1216 &mut mutations_made,
1217 &"".into(),
1218 );
1219 assert_eq!(mutations_made.len(), 0);
1220 }
1221
1222 #[test]
1223 fn test_elvis_literal_operator_does_not_create_mutations() {
1224 let tree = get_ast(KOTLIN_UNARY_REMOVAL_TEST_CODE);
1225 let root = tree.root_node();
1226 let mut mutations_made = Vec::new();
1227 MutationOperators::ElvisLiteralChangeOperator.mutate(
1228 root,
1229 &mut root.walk(),
1230 None,
1231 &mut mutations_made,
1232 &"".into(),
1233 );
1234 assert_eq!(mutations_made.len(), 0);
1235 }
1236
1237 #[test]
1238 fn test_label_removal_operator_does_not_create_mutations() {
1239 let tree = get_ast(KOTLIN_UNARY_REMOVAL_TEST_CODE);
1240 let root = tree.root_node();
1241 let mut mutations_made = Vec::new();
1242 MutationOperators::RemoveLabelOperator.mutate(
1243 root,
1244 &mut root.walk(),
1245 None,
1246 &mut mutations_made,
1247 &"".into(),
1248 );
1249 assert!(mutations_made.is_empty());
1250 }
1251
1252 #[test]
1253 fn test_functional_binary_replacement_operator_does_not_create_mutations() {
1254 let tree = get_ast(KOTLIN_UNARY_REMOVAL_TEST_CODE);
1255 let mutations_made = MutationOperators::FunctionalBinaryReplacementOperator
1256 .find_mutation(&tree, &"file_name".into());
1257 assert!(mutations_made.is_empty());
1258 }
1259
1260 #[test]
1261 fn test_functional_replacement_operator_does_not_create_mutations() {
1262 let tree = get_ast(KOTLIN_UNARY_REMOVAL_TEST_CODE);
1263 let mutations_made = MutationOperators::FunctionalReplacementOperator
1264 .find_mutation(&tree, &"file_name".into());
1265 assert!(mutations_made.is_empty());
1266 }
1267}