mutant_kraken/mutation_tool/
operators.rs

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// The different types of mutation operators that can be performed on a file
16#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
17pub enum MutationOperators {
18    /// Replaces an arithmetic operator with a different arithmetic operator
19    ArithmeticReplacementOperator,
20    /// Removes a unary operator
21    UnaryRemovalOperator,
22    /// Replaces a logical operator with a different logical operator
23    LogicalReplacementOperator,
24    /// Replaces a relational operator with a different relational operator
25    RelationalReplacementOperator,
26    /// Replaces an assignment operator with a different assignment operator
27    AssignmentReplacementOperator,
28    /// Replaces a unary operator with a different unary operator
29    UnaryReplacementOperator,
30    /// Replaces a not null assertion operator with a different not null assertion operator
31    NotNullAssertionOperator,
32    /// Removes an elvis operator
33    ElvisRemoveOperator,
34    /// Changes the literal of an elvis operator
35    ElvisLiteralChangeOperator,
36    /// Changes the literal of a literal
37    LiteralChangeOperator,
38    /// Changes the exception thrown
39    ExceptionChangeOperator,
40    /// Removes a branch from the when statement if the statement has more than one branch
41    WhenRemoveBranchOperator,
42    /// Removes a label when continuing, breaking, or returning
43    RemoveLabelOperator,
44    /// Changes first() to last() and vice versa or find() to findLast() and vice versa
45    FunctionalBinaryReplacementOperator,
46    /// Changes Any() to All() or None() and vice versa or ForEach() to Map() or Filter() and vice versa
47    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    /// Get the operators that correspond to the mutation operator
80    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    /// Get the parent types that are necessary for the mutation operator
174    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    /// Gets all the muatations that can be made to the file based on the the mutation operator
230    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    /// Mutates the given `root` node and its children using the provided `cursor`, `parent`, `mutations_made`, `file_name`, `operators`, and `parent_necessary_types`.
238    ///
239    /// # Arguments
240    ///
241    /// * `root` - A `tree_sitter::Node` representing the root node to mutate.
242    /// * `cursor` - A mutable reference to a `tree_sitter::TreeCursor` used to traverse the syntax tree.
243    /// * `parent` - An optional `tree_sitter::Node` representing the parent node of `root`.
244    /// * `mutations_made` - A mutable reference to a `Vec<Mutation>` that will be populated with any mutations made during the function's execution.
245    /// * `file_name` - A `String` representing the name of the file being mutated.
246    ///
247    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    /// Mutates the given root node based on the specified mutation operators and returns a vector of mutations made.
270    ///
271    /// # Arguments
272    ///
273    /// * `root_node` - A reference to the root node of the AST.
274    /// * `root` - A reference to the root type of the AST.
275    /// * `parent` - An optional reference to the parent type of the AST.
276    /// * `mutation_operators` - A HashSet of mutation operators to apply.
277    /// * `parent_types` - A vector of parent types to check against.
278    /// * `file_name` - The name of the file being mutated.
279    ///
280    /// # Returns
281    ///
282    /// A Result containing a vector of mutations made.
283    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        // Check to see if root type is in the mutation_operators
294        // Check to see if the parent exists
295        // Checks to see if the parent is the necessary kotlin type
296        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                // If the operator is a unary removal operator, we just remove the operator
308                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                // If the operator is a Remove elvis operator, we remove the operator and everything after it
321                // Get the end byte of the end of the line
322                let end_byte = root_node.parent().unwrap().end_byte(); // TODO: remove unwrap
323
324                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                // Create a mutant for all mutation operators
356                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        // Need to make sure the current node is either "any", "all", "none", "forEach", "map", or "filter"
386        // If it is, then we need to change it to the other one
387        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        // Pick a random method that is not the same as the original method
396        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        // Need to make sure the current node is either "first", "last", "firstOrNull", or "lastOrNull"
439        // If it is, then we need to change it to the other one
440        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        // Get the value of the node
469        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 the value is not a label, return
474        if !val.contains('@')
475            && (!val.starts_with("return")
476                || !val.starts_with("continue")
477                || !val.starts_with("break"))
478        {
479            return;
480        }
481
482        // Remove the label
483        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        // Get the when entry list
506        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 the when entry list has more than one entry, remove one of the entries
520        if when_entry_list.len() < 2 {
521            return;
522        }
523
524        // Get a random branch other than the last branch (this is usually the else branch)
525        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        // Remove the node
530        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        // Get the sibling of the root node
550        let sibling = root_node.next_sibling().unwrap();
551        let sibling_type =
552            KotlinTypes::new(sibling.kind()).expect("Failed to convert to KotlinType");
553        // If the sibling is a call expression, i want to grab the simple identifier (its child)
554        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        // Check to see if the child is a simple identifier
561        if child_type != KotlinTypes::SimpleIdentifier {
562            return;
563        }
564        // Get the value
565        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        // Pick a random exception that is not the same as the original exception
573        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        // Change the literal to a different literal
607        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                // Change the value and create a mutation
616                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                // In this case, we need to see the type of the prefix expression, so we need to
630                // Recurse down to the literal
631                self.mutate_literal(node, mutations_made, file_name)
632            }
633            KotlinTypes::StringLiteral => {
634                // Replace the string with a different string
635                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                // Change the value and create a mutation
651                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                // Need to strip off the l at the end
666                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                // Change the value and create a mutation
676                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                // Need to strip off the f at the end
691                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                // Change the value and create a mutation
700                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                // Remove the single quotes and get the value
715                let val = val
716                    .strip_prefix('\'')
717                    .unwrap()
718                    .strip_suffix('\'')
719                    .unwrap()
720                    .chars()
721                    .next()
722                    .unwrap();
723
724                // Get a random character between 'a' and 'z'
725                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    // Generate a random integer different from the original literal
753    let mut random_literal = rng.gen_range(min..max);
754
755    // Ensure the random literal is different from the original
756    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        // Assert that the old operator is not the same as the new operator
815        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        // Assert that the old operator is not the same as the new operator
835        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        // Assert that the old operator is not the same as the new operator
855        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        // Assert that the old operator is not the same as the new operator
875        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        // Assert that the old operator is not the same as the new operator
895        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        // Assert that the old operator is not the same as the new operator
916        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        // Assert that the old operator is not the same as the new operator
935        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        // Create a temp file
944        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        // Assert that the old operator is not the same as the new operator
963        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        // Create a temp file
971        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        // Assert that the old operator is not the same as the new operator
989        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        // Create a temp file
997        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        // Assert that the old operator is not the same as the new operator
1015        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        // Create a temp file
1023        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        // Create a temp file
1045        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        // Create a temp file
1067        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        // Create a temp file
1089        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}