From 31e067de225afe3bbfa87e592e3303caca6de260 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Thu, 23 May 2024 23:08:21 -0400 Subject: [PATCH] feat(parsing_handlers): Add handler to remove comments from merged trees --- .../broken-matching-due-to-comments/base.java | 181 +++++++++++++++++ .../broken-matching-due-to-comments/left.java | 189 ++++++++++++++++++ .../merge.java | 1 + .../right.java | 185 +++++++++++++++++ parsing_handlers/src/java/mod.rs | 6 +- .../src/java/remove_block_comments.rs | 102 ++++++++++ 6 files changed, 663 insertions(+), 1 deletion(-) create mode 100644 bin/tests/scenarios/broken-matching-due-to-comments/base.java create mode 100644 bin/tests/scenarios/broken-matching-due-to-comments/left.java create mode 100644 bin/tests/scenarios/broken-matching-due-to-comments/merge.java create mode 100644 bin/tests/scenarios/broken-matching-due-to-comments/right.java create mode 100644 parsing_handlers/src/java/remove_block_comments.rs diff --git a/bin/tests/scenarios/broken-matching-due-to-comments/base.java b/bin/tests/scenarios/broken-matching-due-to-comments/base.java new file mode 100644 index 0000000..178c8be --- /dev/null +++ b/bin/tests/scenarios/broken-matching-due-to-comments/base.java @@ -0,0 +1,181 @@ +package br.ufpe.cin.mergers.util; + +import java.io.File; + +import br.ufpe.cin.app.JFSTMerge; +import br.ufpe.cin.files.FilesManager; +import de.ovgu.cide.fstgen.ast.FSTNode; +import de.ovgu.cide.fstgen.ast.FSTNonTerminal; +import de.ovgu.cide.fstgen.ast.FSTTerminal; + +/** + * Class representing a textual merge conflict. + * + * @author Guilherme + */ + +public class MergeConflict { + + private final String left; + private final String base; + private final String right; + private final String body; + private final String message; + + private int startLOC; + private int endLOC; + + private File leftOriginFile; + private File baseOriginFile; + private File rightOriginFile; + + private String fullyQualifiedMergedClass; + + public static final String MINE_CONFLICT_MARKER = "<<<<<<< MINE"; + public static final String BASE_CONFLICT_MARKER = "||||||| BASE"; + public static final String CHANGE_CONFLICT_MARKER = "======="; + public static final String YOURS_CONFLICT_MARKER = ">>>>>>> YOURS"; + + public MergeConflict(FSTNode left, FSTNode base, FSTNode right) { + this.left = getNodeContent(left); + this.base = getNodeContent(base); + this.right = getNodeContent(right); + this.message = ""; + this.body = assembleBody(); + } + + private String getNodeContent(FSTNode node) { + if (node == null) { + return ""; + } else if (node instanceof FSTTerminal) { + return IndentationUtils.indentFirstLine((FSTTerminal) node); + } else { + return FilesManager.prettyPrint((FSTNonTerminal) node); + } + } + + private String assembleBody() { + StringBuilder conflict = new StringBuilder(); + conflict.append(MINE_CONFLICT_MARKER) + .append('\n') + .append(left) + .append('\n'); + if(JFSTMerge.showBase) { + conflict.append(BASE_CONFLICT_MARKER) + .append('\n'); + } + conflict.append(CHANGE_CONFLICT_MARKER) + .append(" " + message) + .append('\n') + .append(right) + .append('\n') + .append(YOURS_CONFLICT_MARKER); + return conflict.toString(); + } + + public MergeConflict(FSTTerminal left, FSTTerminal base, FSTTerminal right, int startLOC, int endLOC) { + this(left, base, right); + this.startLOC = startLOC; + this.endLOC = endLOC; + } + + public MergeConflict(String left, String base, String right) { + this.left = left; + this.base = base; + this.right = right; + this.message = ""; + this.body = assembleBody(); + } + + public MergeConflict(String left, String base, String right, int startLOC, int endLOC) { + this(left, base, right); + this.startLOC = startLOC; + this.endLOC = endLOC; + } + + public boolean contains(String leftPattern, String rightPattern) { + if (leftPattern.isEmpty() || rightPattern.isEmpty()) { + return false; + } else { + leftPattern = (leftPattern.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + rightPattern = (rightPattern.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + String lefttrim = (this.left.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + String righttrim = (this.right.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + return (lefttrim.contains(leftPattern) && righttrim.contains(rightPattern)); + } + } + + public void setOriginFiles(File left, File base, File right) { + this.leftOriginFile = left; + this.rightOriginFile = right; + this.baseOriginFile = base; + } + + public String getFullyQualifiedMergedClass() { + return fullyQualifiedMergedClass; + } + + public void setFullyQualifiedMergedClass(String fullyQualifiedMergedClass) { + this.fullyQualifiedMergedClass = fullyQualifiedMergedClass; + } + + @Override + public String toString() { + return this.body; + } + + /** + * @return the LEFT conflicting content + */ + public String getLeft() { + return left; + } + + /** + * @return the BASE conflicting content + */ + public String getBase() { + return base; + } + + /** + * @return the YOURS conflicting content + */ + public String getRight() { + return right; + } + + /** + * @return the startLOC of the conflict + */ + public int getStartLOC() { + return startLOC; + } + + /** + * @return the endLOC + */ + public int getEndLOC() { + return endLOC; + } + + /* + * public boolean containsRelaxed(String leftPattern, String rightPattern){ + * if(leftPattern.isEmpty() || rightPattern.isEmpty()){ return false; } else { + * leftPattern = + * (leftPattern.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); + * rightPattern = + * (rightPattern.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); String + * lefttrim = (this.left.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); + * String righttrim = + * (this.right.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); + * + * leftPattern = Util.removeReservedKeywords(leftPattern); rightPattern = + * Util.removeReservedKeywords(rightPattern); lefttrim = + * Util.removeReservedKeywords(lefttrim); righttrim = + * Util.removeReservedKeywords(righttrim); + * + * return (lefttrim.contains(leftPattern) && righttrim.contains(rightPattern)); + * } } + */ +} diff --git a/bin/tests/scenarios/broken-matching-due-to-comments/left.java b/bin/tests/scenarios/broken-matching-due-to-comments/left.java new file mode 100644 index 0000000..14317d4 --- /dev/null +++ b/bin/tests/scenarios/broken-matching-due-to-comments/left.java @@ -0,0 +1,189 @@ +package br.ufpe.cin.mergers.util; + +import java.io.File; + +import br.ufpe.cin.app.JFSTMerge; +import br.ufpe.cin.files.FilesManager; +import de.ovgu.cide.fstgen.ast.FSTNode; +import de.ovgu.cide.fstgen.ast.FSTNonTerminal; +import de.ovgu.cide.fstgen.ast.FSTTerminal; + +/** + * Class representing a textual merge conflict. + * + * @author Guilherme + */ + +public class MergeConflict { + + private final String left; + private final String base; + private final String right; + private final String body; + private final String message; + + private int startLOC; + private int endLOC; + + private File leftOriginFile; + private File baseOriginFile; + private File rightOriginFile; + + private String fullyQualifiedMergedClass; + + public static final String MINE_CONFLICT_MARKER = "<<<<<<< MINE"; + public static final String BASE_CONFLICT_MARKER = "||||||| BASE"; + public static final String CHANGE_CONFLICT_MARKER = "======="; + public static final String YOURS_CONFLICT_MARKER = ">>>>>>> YOURS"; + + public MergeConflict(FSTNode left, FSTNode base, FSTNode right) { + this.left = getNodeContent(left); + this.base = getNodeContent(base); + this.right = getNodeContent(right); + this.message = ""; + this.body = assembleBody(); + } + + private String getNodeContent(FSTNode node) { + if (node == null) { + return ""; + } else if (node instanceof FSTTerminal) { + return IndentationUtils.indentFirstLine((FSTTerminal) node); + } else { + return FilesManager.prettyPrint((FSTNonTerminal) node); + } + } + + private String assembleBody() { + StringBuilder conflict = new StringBuilder(); + conflict.append(MINE_CONFLICT_MARKER) + .append('\n') + .append(left) + .append('\n'); + if(JFSTMerge.showBase) { + conflict.append(BASE_CONFLICT_MARKER) + .append('\n'); + } + conflict.append(CHANGE_CONFLICT_MARKER) + .append(" " + message) + .append('\n') + .append(right) + .append('\n') + .append(YOURS_CONFLICT_MARKER); + return conflict.toString(); + } + + public MergeConflict(FSTTerminal left, FSTTerminal base, FSTTerminal right, int startLOC, int endLOC) { + this(left, base, right); + this.startLOC = startLOC; + this.endLOC = endLOC; + } + + public MergeConflict(String left, String base, String right) { + this.left = left; + this.base = base; + this.right = right; + this.message = ""; + this.body = assembleBody(); + } + + public MergeConflict(String left, String base, String right, String message) { + this.left = left; + this.base = base; + this.right = right; + this.message = message; + this.body = assembleBody(); + } + + public MergeConflict(String left, String base, String right, int startLOC, int endLOC) { + this(left, base, right); + this.startLOC = startLOC; + this.endLOC = endLOC; + } + + public boolean contains(String leftPattern, String rightPattern) { + if (leftPattern.isEmpty() || rightPattern.isEmpty()) { + return false; + } else { + leftPattern = (leftPattern.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + rightPattern = (rightPattern.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + String lefttrim = (this.left.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + String righttrim = (this.right.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + return (lefttrim.contains(leftPattern) && righttrim.contains(rightPattern)); + } + } + + public void setOriginFiles(File left, File base, File right) { + this.leftOriginFile = left; + this.rightOriginFile = right; + this.baseOriginFile = base; + } + + public String getFullyQualifiedMergedClass() { + return fullyQualifiedMergedClass; + } + + public void setFullyQualifiedMergedClass(String fullyQualifiedMergedClass) { + this.fullyQualifiedMergedClass = fullyQualifiedMergedClass; + } + + @Override + public String toString() { + return this.body; + } + + /** + * @return the LEFT conflicting content + */ + public String getLeft() { + return left; + } + + /** + * @return the BASE conflicting content + */ + public String getBase() { + return base; + } + + /** + * @return the YOURS conflicting content + */ + public String getRight() { + return right; + } + + /** + * @return the startLOC of the conflict + */ + public int getStartLOC() { + return startLOC; + } + + /** + * @return the endLOC + */ + public int getEndLOC() { + return endLOC; + } + + /* + * public boolean containsRelaxed(String leftPattern, String rightPattern){ + * if(leftPattern.isEmpty() || rightPattern.isEmpty()){ return false; } else { + * leftPattern = + * (leftPattern.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); + * rightPattern = + * (rightPattern.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); String + * lefttrim = (this.left.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); + * String righttrim = + * (this.right.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); + * + * leftPattern = Util.removeReservedKeywords(leftPattern); rightPattern = + * Util.removeReservedKeywords(rightPattern); lefttrim = + * Util.removeReservedKeywords(lefttrim); righttrim = + * Util.removeReservedKeywords(righttrim); + * + * return (lefttrim.contains(leftPattern) && righttrim.contains(rightPattern)); + * } } + */ +} diff --git a/bin/tests/scenarios/broken-matching-due-to-comments/merge.java b/bin/tests/scenarios/broken-matching-due-to-comments/merge.java new file mode 100644 index 0000000..2724257 --- /dev/null +++ b/bin/tests/scenarios/broken-matching-due-to-comments/merge.java @@ -0,0 +1 @@ + package br . ufpe . cin . mergers . util ; import java . io . File ; import br . ufpe . cin . app . JFSTMerge ; import br . ufpe . cin . files . FilesManager ; import de . ovgu . cide . fstgen . ast . FSTNode ; import de . ovgu . cide . fstgen . ast . FSTNonTerminal ; import de . ovgu . cide . fstgen . ast . FSTTerminal ; public class MergeConflict { private final String left ; private final String base ; private final String right ; private final String body ; private final String message ; private int startLOC ; private int endLOC ; private File leftOriginFile ; private File baseOriginFile ; private File rightOriginFile ; private String fullyQualifiedMergedClass ; public static final String MINE_CONFLICT_MARKER = "<<<<<<< MINE" ; public static final String BASE_CONFLICT_MARKER = "||||||| BASE" ; public static final String CHANGE_CONFLICT_MARKER = "=======" ; public static final String YOURS_CONFLICT_MARKER = ">>>>>>> YOURS" ; private String getNodeContent ( FSTNode node ) { if ( node == null ) { return "" ; } else if ( node instanceof FSTTerminal ) { return IndentationUtils . indentFirstLine ( ( FSTTerminal ) node ) ; } else { return FilesManager . prettyPrint ( ( FSTNonTerminal ) node ) ; } } private String assembleBody ( ) { StringBuilder conflict = new StringBuilder ( ) ; conflict . append ( MINE_CONFLICT_MARKER ) . append ( '\n' ) . append ( left ) . append ( '\n' ) ; if ( JFSTMerge . showBase ) { conflict . append ( BASE_CONFLICT_MARKER ) . append ( '\n' ) . append ( base ) . append ( '\n' ) ; } conflict . append ( CHANGE_CONFLICT_MARKER ) ; if ( JFSTMerge . showConflictMessages ) { conflict . append ( " " + message ) ; } conflict . append ( '\n' ) . append ( right ) . append ( '\n' ) . append ( YOURS_CONFLICT_MARKER ) ; return conflict . toString ( ) ; } public MergeConflict ( String left , String base , String right , String message ) { this . left = left ; this . base = base ; this . right = right ; this . message = message ; this . body = assembleBody ( ) ; } public boolean contains ( String leftPattern , String rightPattern ) { if ( leftPattern . isEmpty ( ) || rightPattern . isEmpty ( ) ) { return false ; } else { leftPattern = ( leftPattern . replaceAll ( "\\r\\n|\\r|\\n" , "" ) ) . replaceAll ( "\\s+" , "" ) ; rightPattern = ( rightPattern . replaceAll ( "\\r\\n|\\r|\\n" , "" ) ) . replaceAll ( "\\s+" , "" ) ; String lefttrim = ( this . left . replaceAll ( "\\r\\n|\\r|\\n" , "" ) ) . replaceAll ( "\\s+" , "" ) ; String righttrim = ( this . right . replaceAll ( "\\r\\n|\\r|\\n" , "" ) ) . replaceAll ( "\\s+" , "" ) ; return ( lefttrim . contains ( leftPattern ) && righttrim . contains ( rightPattern ) ) ; } } public void setOriginFiles ( File left , File base , File right ) { this . leftOriginFile = left ; this . rightOriginFile = right ; this . baseOriginFile = base ; } public String getFullyQualifiedMergedClass ( ) { return fullyQualifiedMergedClass ; } public void setFullyQualifiedMergedClass ( String fullyQualifiedMergedClass ) { this . fullyQualifiedMergedClass = fullyQualifiedMergedClass ; } @ Override public String toString ( ) { return this . body ; } public String getLeft ( ) { return left ; } public String getBase ( ) { return base ; } public String getRight ( ) { return right ; } public int getStartLOC ( ) { return startLOC ; } public int getEndLOC ( ) { return endLOC ; } public MergeConflict ( FSTNode left , FSTNode base , FSTNode right , String message ) { this . left = getNodeContent ( left ) ; this . base = getNodeContent ( base ) ; this . right = getNodeContent ( right ) ; this . message = message ; this . body = assembleBody ( ) ; } public MergeConflict ( FSTTerminal left , FSTTerminal base , FSTTerminal right , String message , int startLOC , int endLOC ) { this ( left , base , right , message ) ; this . startLOC = startLOC ; this . endLOC = endLOC ; } public MergeConflict ( String left , String base , String right , String message , int startLOC , int endLOC ) { this ( left , base , right , message ) ; this . startLOC = startLOC ; this . endLOC = endLOC ; } } \ No newline at end of file diff --git a/bin/tests/scenarios/broken-matching-due-to-comments/right.java b/bin/tests/scenarios/broken-matching-due-to-comments/right.java new file mode 100644 index 0000000..6771b5e --- /dev/null +++ b/bin/tests/scenarios/broken-matching-due-to-comments/right.java @@ -0,0 +1,185 @@ +package br.ufpe.cin.mergers.util; + +import java.io.File; + +import br.ufpe.cin.app.JFSTMerge; +import br.ufpe.cin.files.FilesManager; +import de.ovgu.cide.fstgen.ast.FSTNode; +import de.ovgu.cide.fstgen.ast.FSTNonTerminal; +import de.ovgu.cide.fstgen.ast.FSTTerminal; + +/** + * Class representing a textual merge conflict. + * + * @author Guilherme + */ + +public class MergeConflict { + + private final String left; + private final String base; + private final String right; + private final String body; + private final String message; + + private int startLOC; + private int endLOC; + + private File leftOriginFile; + private File baseOriginFile; + private File rightOriginFile; + + private String fullyQualifiedMergedClass; + + public static final String MINE_CONFLICT_MARKER = "<<<<<<< MINE"; + public static final String BASE_CONFLICT_MARKER = "||||||| BASE"; + public static final String CHANGE_CONFLICT_MARKER = "======="; + public static final String YOURS_CONFLICT_MARKER = ">>>>>>> YOURS"; + + public MergeConflict(FSTNode left, FSTNode base, FSTNode right, String message) { + this.left = getNodeContent(left); + this.base = getNodeContent(base); + this.right = getNodeContent(right); + this.message = message; + this.body = assembleBody(); + } + + private String getNodeContent(FSTNode node) { + if (node == null) { + return ""; + } else if (node instanceof FSTTerminal) { + return IndentationUtils.indentFirstLine((FSTTerminal) node); + } else { + return FilesManager.prettyPrint((FSTNonTerminal) node); + } + } + + private String assembleBody() { + StringBuilder conflict = new StringBuilder(); + conflict.append(MINE_CONFLICT_MARKER) + .append('\n') + .append(left) + .append('\n'); + if(JFSTMerge.showBase) { + conflict.append(BASE_CONFLICT_MARKER) + .append('\n') + .append(base) + .append('\n'); + } + conflict.append(CHANGE_CONFLICT_MARKER); + if(JFSTMerge.showConflictMessages) { + conflict.append(" " + message); + } + conflict.append('\n') + .append(right) + .append('\n') + .append(YOURS_CONFLICT_MARKER); + return conflict.toString(); + } + + public MergeConflict(FSTTerminal left, FSTTerminal base, FSTTerminal right, String message, int startLOC, int endLOC) { + this(left, base, right, message); + this.startLOC = startLOC; + this.endLOC = endLOC; + } + + public MergeConflict(String left, String base, String right, String message) { + this.left = left; + this.base = base; + this.right = right; + this.message = message; + this.body = assembleBody(); + } + + public MergeConflict(String left, String base, String right, String message, int startLOC, int endLOC) { + this(left, base, right, message); + this.startLOC = startLOC; + this.endLOC = endLOC; + } + + public boolean contains(String leftPattern, String rightPattern) { + if (leftPattern.isEmpty() || rightPattern.isEmpty()) { + return false; + } else { + leftPattern = (leftPattern.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + rightPattern = (rightPattern.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + String lefttrim = (this.left.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + String righttrim = (this.right.replaceAll("\\r\\n|\\r|\\n", "")).replaceAll("\\s+", ""); + return (lefttrim.contains(leftPattern) && righttrim.contains(rightPattern)); + } + } + + public void setOriginFiles(File left, File base, File right) { + this.leftOriginFile = left; + this.rightOriginFile = right; + this.baseOriginFile = base; + } + + public String getFullyQualifiedMergedClass() { + return fullyQualifiedMergedClass; + } + + public void setFullyQualifiedMergedClass(String fullyQualifiedMergedClass) { + this.fullyQualifiedMergedClass = fullyQualifiedMergedClass; + } + + @Override + public String toString() { + return this.body; + } + + /** + * @return the LEFT conflicting content + */ + public String getLeft() { + return left; + } + + /** + * @return the BASE conflicting content + */ + public String getBase() { + return base; + } + + /** + * @return the YOURS conflicting content + */ + public String getRight() { + return right; + } + + /** + * @return the startLOC of the conflict + */ + public int getStartLOC() { + return startLOC; + } + + /** + * @return the endLOC + */ + public int getEndLOC() { + return endLOC; + } + + /* + * public boolean containsRelaxed(String leftPattern, String rightPattern){ + * if(leftPattern.isEmpty() || rightPattern.isEmpty()){ return false; } else { + * leftPattern = + * (leftPattern.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); + * rightPattern = + * (rightPattern.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); String + * lefttrim = (this.left.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); + * String righttrim = + * (this.right.replaceAll("\\r\\n|\\r|\\n","")).replaceAll("\\s+",""); + * + * leftPattern = Util.removeReservedKeywords(leftPattern); rightPattern = + * Util.removeReservedKeywords(rightPattern); lefttrim = + * Util.removeReservedKeywords(lefttrim); righttrim = + * Util.removeReservedKeywords(righttrim); + * + * return (lefttrim.contains(leftPattern) && righttrim.contains(rightPattern)); + * } } + */ +} diff --git a/parsing_handlers/src/java/mod.rs b/parsing_handlers/src/java/mod.rs index 311f7fa..1de8bcb 100644 --- a/parsing_handlers/src/java/mod.rs +++ b/parsing_handlers/src/java/mod.rs @@ -1,7 +1,11 @@ +mod remove_block_comments; mod tweak_import_declarations; use crate::ParsingHandlers; pub fn get_default_java_parsing_handlers() -> ParsingHandlers { - ParsingHandlers::new(vec![tweak_import_declarations::tweak_import_declarations]) + ParsingHandlers::new(vec![ + tweak_import_declarations::tweak_import_declarations, + remove_block_comments::remove_block_comments, + ]) } diff --git a/parsing_handlers/src/java/remove_block_comments.rs b/parsing_handlers/src/java/remove_block_comments.rs new file mode 100644 index 0000000..2d12a41 --- /dev/null +++ b/parsing_handlers/src/java/remove_block_comments.rs @@ -0,0 +1,102 @@ +use model::{cst_node::NonTerminal, CSTNode}; + +pub fn remove_block_comments(root: CSTNode<'_>) -> CSTNode<'_> { + match root { + CSTNode::Terminal(_) => root, + CSTNode::NonTerminal(non_terminal) => CSTNode::NonTerminal(NonTerminal { + id: non_terminal.id, + kind: non_terminal.kind, + start_position: non_terminal.start_position, + end_position: non_terminal.end_position, + children: non_terminal + .children + .into_iter() + .filter(|node| node.kind() != "block_comment" && node.kind() != "line_comment") + .map(|node| remove_block_comments(node)) + .collect(), + are_children_unordered: non_terminal.are_children_unordered, + }), + } +} + +#[cfg(test)] +mod tests { + use model::{ + cst_node::{NonTerminal, Terminal}, + CSTNode, + }; + + #[test] + fn it_removes_first_level_comments() { + let root = CSTNode::NonTerminal(NonTerminal { + children: vec![ + CSTNode::Terminal(Terminal { + kind: "block_comment", + ..Default::default() + }), + CSTNode::Terminal(Terminal { + kind: "line_comment", + ..Default::default() + }), + CSTNode::Terminal(Terminal { + kind: "program", + ..Default::default() + }), + ], + ..Default::default() + }); + + let expected_root = CSTNode::NonTerminal(NonTerminal { + children: vec![CSTNode::Terminal(Terminal { + kind: "program", + ..Default::default() + })], + ..Default::default() + }); + + assert_eq!( + super::remove_block_comments(root).contents(), + expected_root.contents() + ); + } + + #[test] + fn it_removes_deep_comments() { + let root = CSTNode::NonTerminal(NonTerminal { + children: vec![CSTNode::NonTerminal(NonTerminal { + children: vec![ + CSTNode::Terminal(Terminal { + kind: "block_comment", + ..Default::default() + }), + CSTNode::Terminal(Terminal { + kind: "line_comment", + ..Default::default() + }), + CSTNode::Terminal(Terminal { + kind: "program", + ..Default::default() + }), + ], + ..Default::default() + })], + ..Default::default() + }); + + let expected_root = CSTNode::NonTerminal(NonTerminal { + children: vec![CSTNode::NonTerminal(NonTerminal { + children: vec![CSTNode::Terminal(Terminal { + kind: "program", + ..Default::default() + })], + ..Default::default() + })], + ..Default::default() + }); + + assert_eq!( + super::remove_block_comments(root).contents(), + expected_root.contents() + ); + } +}