1 package com.github.javaparser.printer.lexicalpreservation; 2 3 import com.github.javaparser.GeneratedJavaParserConstants; 4 import com.github.javaparser.ast.Modifier; 5 import com.github.javaparser.ast.Node; 6 import com.github.javaparser.ast.PackageDeclaration; 7 import com.github.javaparser.ast.body.AnnotationDeclaration; 8 import com.github.javaparser.ast.body.EnumConstantDeclaration; 9 import com.github.javaparser.ast.body.EnumDeclaration; 10 import com.github.javaparser.ast.body.MethodDeclaration; 11 import com.github.javaparser.ast.comments.JavadocComment; 12 import com.github.javaparser.ast.expr.*; 13 import com.github.javaparser.ast.observer.ObservableProperty; 14 import com.github.javaparser.ast.stmt.BlockStmt; 15 import com.github.javaparser.ast.stmt.ExpressionStmt; 16 import com.github.javaparser.ast.stmt.Statement; 17 import com.github.javaparser.printer.ConcreteSyntaxModel; 18 import com.github.javaparser.printer.concretesyntaxmodel.CsmElement; 19 import com.github.javaparser.printer.concretesyntaxmodel.CsmToken; 20 import org.junit.Test; 21 22 import java.io.IOException; 23 import java.util.EnumSet; 24 25 import static com.github.javaparser.TokenTypes.eolTokenKind; 26 import static com.github.javaparser.TokenTypes.spaceTokenKind; 27 import static org.junit.Assert.assertEquals; 28 import static org.junit.Assert.assertTrue; 29 30 public class LexicalDifferenceCalculatorTest extends AbstractLexicalPreservingTest { 31 32 @Test 33 public void compilationUnitExampleOriginal() { 34 considerCode("class A {}"); 35 CsmElement element = ConcreteSyntaxModel.forClass(cu.getClass()); 36 LexicalDifferenceCalculator.CalculatedSyntaxModel csmOriginal = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(element, cu); 37 assertEquals(2, csmOriginal.elements.size()); 38 assertEquals(new LexicalDifferenceCalculator.CsmChild(cu.getType(0)), csmOriginal.elements.get(0)); 39 assertEquals(new CsmToken(eolTokenKind()), csmOriginal.elements.get(1)); 40 } 41 42 @Test 43 public void compilationUnitExampleWithPackageSet() { 44 considerCode("class A {}"); 45 CsmElement element = ConcreteSyntaxModel.forClass(cu.getClass()); 46 PackageDeclaration packageDeclaration = new PackageDeclaration(new Name(new Name("foo"), "bar")); 47 LexicalDifferenceCalculator.CalculatedSyntaxModel csmChanged = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(element, cu, ObservableProperty.PACKAGE_DECLARATION, null, packageDeclaration); 48 assertEquals(3, csmChanged.elements.size()); 49 assertEquals(new LexicalDifferenceCalculator.CsmChild(packageDeclaration), csmChanged.elements.get(0)); 50 assertEquals(new LexicalDifferenceCalculator.CsmChild(cu.getType(0)), csmChanged.elements.get(1)); 51 assertEquals(new CsmToken(eolTokenKind()), csmChanged.elements.get(2)); 52 } 53 54 @Test 55 public void annotationDeclarationModifiersExampleOriginal() throws IOException { 56 considerExample("AnnotationDeclaration_Example1_original"); 57 AnnotationDeclaration annotationDeclaration = (AnnotationDeclaration)cu.getType(0); 58 CsmElement element = ConcreteSyntaxModel.forClass(annotationDeclaration.getClass()); 59 LexicalDifferenceCalculator.CalculatedSyntaxModel csm = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(element, annotationDeclaration); 60 csm.removeIndentationElements(); 61 int i = 0; 62 assertEquals(new CsmToken(GeneratedJavaParserConstants.AT), csm.elements.get(i++)); 63 assertEquals(new CsmToken(GeneratedJavaParserConstants.INTERFACE), csm.elements.get(i++)); 64 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 65 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getName()), csm.elements.get(i++)); 66 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 67 assertEquals(new CsmToken(GeneratedJavaParserConstants.LBRACE), csm.elements.get(i++)); 68 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 69 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(0)), csm.elements.get(i++)); 70 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 71 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(1)), csm.elements.get(i++)); 72 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 73 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(2)), csm.elements.get(i++)); 74 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 75 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(3)), csm.elements.get(i++)); 76 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 77 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(4)), csm.elements.get(i++)); 78 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 79 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(5)), csm.elements.get(i++)); 80 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 81 assertEquals(new CsmToken(GeneratedJavaParserConstants.RBRACE), csm.elements.get(i++)); 82 assertEquals(i, csm.elements.size()); 83 } 84 85 @Test 86 public void annotationDeclarationModifiersExampleModified() throws IOException { 87 considerExample("AnnotationDeclaration_Example1_original"); 88 AnnotationDeclaration annotationDeclaration = (AnnotationDeclaration)cu.getType(0); 89 CsmElement element = ConcreteSyntaxModel.forClass(annotationDeclaration.getClass()); 90 LexicalDifferenceCalculator.CalculatedSyntaxModel csm = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(element, annotationDeclaration, ObservableProperty.MODIFIERS, EnumSet.noneOf(Modifier.class), EnumSet.of(Modifier.PUBLIC)); 91 csm.removeIndentationElements(); 92 int i = 0; 93 assertEquals(new CsmToken(GeneratedJavaParserConstants.PUBLIC), csm.elements.get(i++)); 94 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 95 assertEquals(new CsmToken(GeneratedJavaParserConstants.AT), csm.elements.get(i++)); 96 assertEquals(new CsmToken(GeneratedJavaParserConstants.INTERFACE), csm.elements.get(i++)); 97 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 98 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getName()), csm.elements.get(i++)); 99 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 100 assertEquals(new CsmToken(GeneratedJavaParserConstants.LBRACE), csm.elements.get(i++)); 101 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 102 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(0)), csm.elements.get(i++)); 103 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 104 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(1)), csm.elements.get(i++)); 105 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 106 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(2)), csm.elements.get(i++)); 107 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 108 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(3)), csm.elements.get(i++)); 109 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 110 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(4)), csm.elements.get(i++)); 111 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 112 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(5)), csm.elements.get(i++)); 113 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 114 assertEquals(new CsmToken(GeneratedJavaParserConstants.RBRACE), csm.elements.get(i++)); 115 assertEquals(i, csm.elements.size()); 116 } 117 118 @Test 119 public void annotationDeclarationNameExampleModified() throws IOException { 120 considerExample("AnnotationDeclaration_Example1_original"); 121 AnnotationDeclaration annotationDeclaration = (AnnotationDeclaration)cu.getType(0); 122 CsmElement element = ConcreteSyntaxModel.forClass(annotationDeclaration.getClass()); 123 SimpleName newName = new SimpleName("NewName"); 124 LexicalDifferenceCalculator.CalculatedSyntaxModel csm = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(element, annotationDeclaration, ObservableProperty.NAME, 125 annotationDeclaration.getName(), newName); 126 csm.removeIndentationElements(); 127 int i = 0; 128 assertEquals(new CsmToken(GeneratedJavaParserConstants.AT), csm.elements.get(i++)); 129 assertEquals(new CsmToken(GeneratedJavaParserConstants.INTERFACE), csm.elements.get(i++)); 130 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 131 assertEquals(new LexicalDifferenceCalculator.CsmChild(newName), csm.elements.get(i++)); 132 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 133 assertEquals(new CsmToken(GeneratedJavaParserConstants.LBRACE), csm.elements.get(i++)); 134 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 135 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(0)), csm.elements.get(i++)); 136 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 137 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(1)), csm.elements.get(i++)); 138 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 139 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(2)), csm.elements.get(i++)); 140 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 141 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(3)), csm.elements.get(i++)); 142 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 143 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(4)), csm.elements.get(i++)); 144 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 145 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(5)), csm.elements.get(i++)); 146 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 147 assertEquals(new CsmToken(GeneratedJavaParserConstants.RBRACE), csm.elements.get(i++)); 148 assertEquals(i, csm.elements.size()); 149 } 150 151 @Test 152 public void annotationDeclaratioJavadocExampleOriginal() throws IOException { 153 considerExample("AnnotationDeclaration_Example3_original"); 154 AnnotationDeclaration annotationDeclaration = (AnnotationDeclaration)cu.getType(0); 155 CsmElement element = ConcreteSyntaxModel.forClass(annotationDeclaration.getClass()); 156 LexicalDifferenceCalculator.CalculatedSyntaxModel csm = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(element, annotationDeclaration); 157 csm.removeIndentationElements(); 158 int i = 0; 159 assertEquals(new CsmToken(GeneratedJavaParserConstants.PUBLIC), csm.elements.get(i++)); 160 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 161 assertEquals(new CsmToken(GeneratedJavaParserConstants.AT), csm.elements.get(i++)); 162 assertEquals(new CsmToken(GeneratedJavaParserConstants.INTERFACE), csm.elements.get(i++)); 163 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 164 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getName()), csm.elements.get(i++)); 165 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 166 assertEquals(new CsmToken(GeneratedJavaParserConstants.LBRACE), csm.elements.get(i++)); 167 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 168 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(0)), csm.elements.get(i++)); 169 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 170 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(1)), csm.elements.get(i++)); 171 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 172 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(2)), csm.elements.get(i++)); 173 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 174 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(3)), csm.elements.get(i++)); 175 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 176 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(4)), csm.elements.get(i++)); 177 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 178 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(5)), csm.elements.get(i++)); 179 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 180 assertEquals(new CsmToken(GeneratedJavaParserConstants.RBRACE), csm.elements.get(i++)); 181 assertEquals(i, csm.elements.size()); 182 } 183 184 @Test 185 public void annotationDeclaratioJavadocExampleAddingJavadoc() throws IOException { 186 considerExample("AnnotationDeclaration_Example3_original"); 187 AnnotationDeclaration annotationDeclaration = (AnnotationDeclaration)cu.getType(0); 188 CsmElement element = ConcreteSyntaxModel.forClass(annotationDeclaration.getClass()); 189 JavadocComment comment = new JavadocComment("Cool this annotation!"); 190 LexicalDifferenceCalculator.CalculatedSyntaxModel csm = new LexicalDifferenceCalculator().calculatedSyntaxModelAfterPropertyChange(element, annotationDeclaration, ObservableProperty.COMMENT, null, comment); 191 csm.removeIndentationElements(); 192 int i = 0; 193 assertEquals(new CsmToken(GeneratedJavaParserConstants.PUBLIC), csm.elements.get(i++)); 194 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 195 assertEquals(new CsmToken(GeneratedJavaParserConstants.AT), csm.elements.get(i++)); 196 assertEquals(new CsmToken(GeneratedJavaParserConstants.INTERFACE), csm.elements.get(i++)); 197 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 198 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getName()), csm.elements.get(i++)); 199 assertEquals(new CsmToken(spaceTokenKind()), csm.elements.get(i++)); 200 assertEquals(new CsmToken(GeneratedJavaParserConstants.LBRACE), csm.elements.get(i++)); 201 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 202 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(0)), csm.elements.get(i++)); 203 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 204 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(1)), csm.elements.get(i++)); 205 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 206 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(2)), csm.elements.get(i++)); 207 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 208 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(3)), csm.elements.get(i++)); 209 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 210 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(4)), csm.elements.get(i++)); 211 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 212 assertEquals(new LexicalDifferenceCalculator.CsmChild(annotationDeclaration.getMember(5)), csm.elements.get(i++)); 213 assertEquals(new CsmToken(eolTokenKind()), csm.elements.get(i++)); 214 assertEquals(new CsmToken(GeneratedJavaParserConstants.RBRACE), csm.elements.get(i++)); 215 assertEquals(i, csm.elements.size()); 216 } 217 218 @Test 219 public void simpleEnumConstantDeclaration() throws IOException { 220 EnumConstantDeclaration ecd = considerEcd("A"); 221 LexicalDifferenceCalculator.CalculatedSyntaxModel csm = new LexicalDifferenceCalculator().calculatedSyntaxModelForNode(ecd); 222 223 int i = 0; 224 assertEquals(new LexicalDifferenceCalculator.CsmChild(ecd.getName()), csm.elements.get(i++)); 225 assertEquals(i, csm.elements.size()); 226 } 227 228 @Test 229 public void csmModelAfterAddingStatementToEmptyBlock() throws IOException { 230 LexicalDifferenceCalculator ldc = new LexicalDifferenceCalculator(); 231 considerExample("ASimpleClassWithMoreFormatting_step3"); 232 233 MethodDeclaration setter = cu.getClassByName("MyRenamedClass").get() 234 .getMethodsByName("setAField").get(0); 235 Statement assignStatement = new ExpressionStmt( 236 new AssignExpr( 237 new FieldAccessExpr(new ThisExpr(),"aField"), 238 new NameExpr("aField"), 239 AssignExpr.Operator.ASSIGN 240 )); 241 LexicalDifferenceCalculator.CalculatedSyntaxModel calculatedSyntaxModel = 242 ldc.calculatedSyntaxModelAfterListAddition( 243 ConcreteSyntaxModel.forClass(BlockStmt.class), 244 ObservableProperty.STATEMENTS, 245 setter.getBody().get().getStatements(), 246 0, 247 assignStatement); 248 int index = 0; 249 assertEquals(CsmElement.token(GeneratedJavaParserConstants.LBRACE), calculatedSyntaxModel.elements.get(index++)); 250 assertEquals(CsmElement.newline(), calculatedSyntaxModel.elements.get(index++)); 251 assertEquals(CsmElement.indent(), calculatedSyntaxModel.elements.get(index++)); 252 assertTrue(isChild(calculatedSyntaxModel.elements.get(index++), ExpressionStmt.class)); 253 assertEquals(CsmElement.newline(), calculatedSyntaxModel.elements.get(index++)); 254 assertEquals(CsmElement.unindent(), calculatedSyntaxModel.elements.get(index++)); 255 assertEquals(CsmElement.token(GeneratedJavaParserConstants.RBRACE), calculatedSyntaxModel.elements.get(index++)); 256 assertEquals(index, calculatedSyntaxModel.elements.size()); 257 } 258 259 @Test 260 public void differenceAfterddingStatementToEmptyBlock() throws IOException { 261 LexicalDifferenceCalculator ldc = new LexicalDifferenceCalculator(); 262 considerExample("ASimpleClassWithMoreFormatting_step3"); 263 264 MethodDeclaration setter = cu.getClassByName("MyRenamedClass").get() 265 .getMethodsByName("setAField").get(0); 266 Statement assignStatement = new ExpressionStmt( 267 new AssignExpr( 268 new FieldAccessExpr(new ThisExpr(),"aField"), 269 new NameExpr("aField"), 270 AssignExpr.Operator.ASSIGN 271 )); 272 Difference diff = ldc.calculateListAdditionDifference( 273 ObservableProperty.STATEMENTS, 274 setter.getBody().get().getStatements(), 275 0, 276 assignStatement); 277 int index = 0; 278 assertEquals(Difference.DifferenceElement.kept(CsmElement.token(GeneratedJavaParserConstants.LBRACE)), diff.getElements().get(index++)); 279 assertEquals(Difference.DifferenceElement.kept(CsmElement.newline()), diff.getElements().get(index++)); 280 assertEquals(Difference.DifferenceElement.added(CsmElement.indent()), diff.getElements().get(index++)); 281 assertTrue(isAddedChild(diff.getElements().get(index++), ExpressionStmt.class)); 282 assertEquals(Difference.DifferenceElement.added(CsmElement.newline()), diff.getElements().get(index++)); 283 assertEquals(Difference.DifferenceElement.added(CsmElement.unindent()), diff.getElements().get(index++)); 284 assertEquals(Difference.DifferenceElement.kept(CsmElement.token(GeneratedJavaParserConstants.RBRACE)), diff.getElements().get(index++)); 285 assertEquals(index, diff.getElements().size()); 286 } 287 288 private boolean isAddedChild(Difference.DifferenceElement element, Class<? extends Node> childClass) { 289 return element.isAdded() && isChild(element.getElement(), childClass); 290 } 291 292 private boolean isChild(CsmElement element, Class<? extends Node> childClass) { 293 return element instanceof LexicalDifferenceCalculator.CsmChild && childClass.isInstance(((LexicalDifferenceCalculator.CsmChild)element).getChild()); 294 } 295 296 protected EnumConstantDeclaration considerEcd(String code) { 297 considerCode("enum A { " + code + " }"); 298 return ((EnumDeclaration)cu.getType(0)).getEntries().get(0); 299 } 300 } 301