From f0fdc59195acf0316b7017153d6a5f64d3eebfda Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Thu, 22 May 2014 11:55:26 +0400 Subject: [PATCH] IDEA-124590 Java Rearranger: Implement "section" support --- .../arrangement/JavaArrangementVisitor.java | 121 +- .../codeStyle/arrangement/JavaRearranger.java | 31 +- .../JavaSectionArrangementEntry.java | 41 + .../JavaRearrangerSectionsTest.groovy | 1026 +++++++++++++++++ 4 files changed, 1182 insertions(+), 37 deletions(-) create mode 100644 java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaSectionArrangementEntry.java create mode 100644 java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerSectionsTest.groovy diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java index bd56761a3292..d6dfdba299d4 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java @@ -18,11 +18,13 @@ package com.intellij.psi.codeStyle.arrangement; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.arrangement.group.ArrangementGroupingRule; import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken; import com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens; import com.intellij.psi.search.searches.SuperMethodsSearch; import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; import com.intellij.psi.util.PropertyUtil; +import com.intellij.util.Consumer; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; @@ -32,6 +34,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; +import static com.intellij.psi.codeStyle.arrangement.ArrangementSectionDetector.ArrangementSectionEntryTemplate; import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.EntryType.*; import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Modifier.*; @@ -61,24 +64,56 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { @NotNull private final Collection myRanges; @NotNull private final Set myGroupingRules; @NotNull private final MethodBodyProcessor myMethodBodyProcessor; + @NotNull private final ArrangementSectionDetector mySectionDetector; @Nullable private final Document myDocument; @Nullable private Set classFields; + @NotNull private Set myProcessedSectionsComments = ContainerUtil.newHashSet(); + public JavaArrangementVisitor(@NotNull JavaArrangementParseInfo infoHolder, @Nullable Document document, @NotNull Collection ranges, - @NotNull Set groupingRules) + @NotNull ArrangementSettings settings) { myInfo = infoHolder; myDocument = document; myRanges = ranges; - myGroupingRules = groupingRules; + myGroupingRules = getGroupingRules(settings); + myMethodBodyProcessor = new MethodBodyProcessor(infoHolder); + mySectionDetector = new ArrangementSectionDetector(document, settings, new Consumer() { + @Override + public void consume(ArrangementSectionEntryTemplate data) { + TextRange range = data.getTextRange(); + JavaSectionArrangementEntry entry = new JavaSectionArrangementEntry(getCurrent(), data.getToken(), range, data.getText(), true); + registerEntry(data.getElement(), entry); + } + }); + } + + @Override + public void visitComment(PsiComment comment) { + if (myProcessedSectionsComments.contains(comment)) { + return; + } + mySectionDetector.processComment(comment); + } + + @NotNull + private static Set getGroupingRules(@NotNull ArrangementSettings settings) { + Set groupingRules = ContainerUtilRt.newHashSet(); + for (ArrangementGroupingRule rule : settings.getGroupings()) { + groupingRules.add(rule.getGroupingType()); + } + return groupingRules; } @Override public void visitClass(PsiClass aClass) { + boolean isSectionCommentsDetected = registerSectionComments(aClass); + TextRange range = isSectionCommentsDetected ? getElementRangeWithoutComments(aClass) : aClass.getTextRange(); + ArrangementSettingsToken type = CLASS; if (aClass.isEnum()) { type = ENUM; @@ -86,7 +121,7 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { else if (aClass.isInterface()) { type = INTERFACE; } - JavaElementArrangementEntry entry = createNewEntry(aClass, aClass.getTextRange(), type, aClass.getName(), true); + JavaElementArrangementEntry entry = createNewEntry(aClass, range, type, aClass.getName(), true); processEntry(entry, aClass, aClass); } @@ -104,6 +139,8 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { @Override public void visitField(PsiField field) { + boolean isSectionCommentsDetected = registerSectionComments(field); + // There is a possible case that more than one field is declared for the same type like 'int i, j;'. We want to process only // the first one then. PsiElement fieldPrev = getPreviousNonWsComment(field.getPrevSibling(), 0); @@ -115,7 +152,7 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { // int i1, // i2; // We want to consider only the first declaration then but need to expand its range to all affected lines (up to semicolon). - TextRange range = field.getTextRange(); + TextRange range = isSectionCommentsDetected ? getElementRangeWithoutComments(field) : field.getTextRange(); PsiElement child = field.getLastChild(); boolean needSpecialProcessing = true; if (isSemicolon(child)) { @@ -128,7 +165,7 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { PsiElement prev = getPreviousNonWsComment(child, range.getStartOffset()); needSpecialProcessing = prev != null && !isSemicolon(prev); } - + if (needSpecialProcessing) { for (PsiElement e = field.getNextSibling(); e != null; e = e.getNextSibling()) { if (e instanceof PsiWhiteSpace || e instanceof PsiComment) { // Skip white space and comment @@ -283,14 +320,48 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { } } + @NotNull + public static TextRange getElementRangeWithoutComments(@NotNull PsiElement element) { + PsiElement[] children = element.getChildren(); + assert(children.length > 1 && children[0] instanceof PsiComment); + + int i = 0; + PsiElement child = children[i]; + while (child instanceof PsiWhiteSpace || child instanceof PsiComment) { + child = children[++i]; + } + + return new TextRange(child.getTextRange().getStartOffset(), element.getTextRange().getEndOffset()); + } + + @NotNull + public static List getComments(@NotNull PsiElement element) { + PsiElement[] children = element.getChildren(); + List comments = ContainerUtil.newArrayList(); + + for (PsiElement e : children) { + if (e instanceof PsiComment) { + comments.add((PsiComment)e); + } else if (!(e instanceof PsiWhiteSpace)) { + return comments; + } + } + + return comments; + } + @Override public void visitMethod(PsiMethod method) { + boolean isSectionCommentsDetected = registerSectionComments(method); + final TextRange range = isSectionCommentsDetected ? getElementRangeWithoutComments(method) + : method.getTextRange(); + ArrangementSettingsToken type = method.isConstructor() ? CONSTRUCTOR : METHOD; - JavaElementArrangementEntry entry = createNewEntry(method, method.getTextRange(), type, method.getName(), true); + JavaElementArrangementEntry entry = createNewEntry(method, range, type, method.getName(), true); if (entry == null) { return; } - + processEntry(entry, method, method.getBody()); parseProperties(method, entry); myInfo.onMethodEntryCreated(method, entry); @@ -309,6 +380,18 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { } } + private boolean registerSectionComments(@NotNull PsiElement element) { + List comments = getComments(element); + boolean isSectionCommentsDetected = false; + for (PsiComment comment : comments) { + if (mySectionDetector.processComment(comment)) { + isSectionCommentsDetected = true; + myProcessedSectionsComments.add(comment); + } + } + return isSectionCommentsDetected; + } + private void parseProperties(PsiMethod method, JavaElementArrangementEntry entry) { if (!myGroupingRules.contains(StdArrangementTokens.Grouping.GETTERS_AND_SETTERS)) { return; @@ -370,7 +453,18 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { myStack.pop(); } } - + + private void registerEntry(@NotNull PsiElement element, @NotNull JavaElementArrangementEntry entry) { + myEntries.put(element, entry); + DefaultArrangementEntry current = getCurrent(); + if (current == null) { + myInfo.addEntry(entry); + } + else { + current.addChild(entry); + } + } + @Nullable private JavaElementArrangementEntry createNewEntry(@NotNull PsiElement element, @NotNull TextRange range, @@ -391,14 +485,7 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { else { entry = new JavaElementArrangementEntry(current, range, type, name, false); } - myEntries.put(element, entry); - if (current == null) { - myInfo.addEntry(entry); - } - else { - current.addChild(entry); - } - + registerEntry(element, entry); return entry; } @@ -433,7 +520,7 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { entry.addModifier(PACKAGE_PRIVATE); } } - + private static class MethodBodyProcessor extends JavaRecursiveElementVisitor { @NotNull private final JavaArrangementParseInfo myInfo; diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java index 577bd62443de..e35cc50379dd 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java @@ -55,7 +55,10 @@ import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Ge * @author Denis Zhdanov * @since 7/20/12 2:31 PM */ -public class JavaRearranger implements Rearranger, ArrangementStandardSettingsAware, ArrangementColorsAware { +public class JavaRearranger implements Rearranger, + ArrangementSectionRuleAwareSettings, + ArrangementStandardSettingsAware, + ArrangementColorsAware { // Type @NotNull private static final Set SUPPORTED_TYPES = @@ -215,12 +218,11 @@ public class JavaRearranger implements Rearranger, @NotNull PsiElement element, @NotNull ArrangementSettings settings) { - Set groupingRules = getGroupingRules(settings); JavaArrangementParseInfo existingEntriesInfo = new JavaArrangementParseInfo(); - root.accept(new JavaArrangementVisitor(existingEntriesInfo, document, ranges, groupingRules)); + root.accept(new JavaArrangementVisitor(existingEntriesInfo, document, ranges, settings)); JavaArrangementParseInfo newEntryInfo = new JavaArrangementParseInfo(); - element.accept(new JavaArrangementVisitor(newEntryInfo, document, Collections.singleton(element.getTextRange()), groupingRules)); + element.accept(new JavaArrangementVisitor(newEntryInfo, document, Collections.singleton(element.getTextRange()), settings)); if (newEntryInfo.getEntries().size() != 1) { return null; } @@ -236,7 +238,7 @@ public class JavaRearranger implements Rearranger, { // Following entries are subject to arrangement: class, interface, field, method. JavaArrangementParseInfo parseInfo = new JavaArrangementParseInfo(); - root.accept(new JavaArrangementVisitor(parseInfo, document, ranges, getGroupingRules(settings))); + root.accept(new JavaArrangementVisitor(parseInfo, document, ranges, settings)); for (ArrangementGroupingRule rule : settings.getGroupings()) { if (GETTERS_AND_SETTERS.equals(rule.getGroupingType())) { setupGettersAndSetters(parseInfo); @@ -298,17 +300,6 @@ public class JavaRearranger implements Rearranger, } } - @NotNull - private static Set getGroupingRules(@Nullable ArrangementSettings settings) { - Set groupingRules = ContainerUtilRt.newHashSet(); - if (settings != null) { - for (ArrangementGroupingRule rule : settings.getGroupings()) { - groupingRules.add(rule.getGroupingType()); - } - } - return groupingRules; - } - @NotNull @Override public ArrangementSettingsSerializer getSerializer() { @@ -341,7 +332,7 @@ public class JavaRearranger implements Rearranger, new CompositeArrangementSettingsToken(ORDER, KEEP, BY_NAME) ); } - + @Override public boolean isEnabled(@NotNull ArrangementSettingsToken token, @Nullable ArrangementMatchCondition current) { if (SUPPORTED_TYPES.contains(token) || SUPPORTED_ORDERS.contains(token) || StdArrangementTokens.Regexp.NAME.equals(token)) { @@ -411,11 +402,11 @@ public class JavaRearranger implements Rearranger, if (attributes == null) { continue; } - + if (result == null) { result = attributes; } - + Color currentForegroundColor = result.getForegroundColor(); if (currentForegroundColor == null) { result.setForegroundColor(attributes.getForegroundColor()); @@ -434,7 +425,7 @@ public class JavaRearranger implements Rearranger, if (result != null && result.getForegroundColor() == null) { return null; } - + if (result != null && result.getBackgroundColor() == null) { result.setBackgroundColor(scheme.getDefaultBackground()); } diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaSectionArrangementEntry.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaSectionArrangementEntry.java new file mode 100644 index 000000000000..17daf4ac8ba8 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaSectionArrangementEntry.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.codeStyle.arrangement; + +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class JavaSectionArrangementEntry extends JavaElementArrangementEntry implements TextAwareArrangementEntry { + @NotNull private final String myText; + + public JavaSectionArrangementEntry(@Nullable ArrangementEntry parent, + @NotNull ArrangementSettingsToken type, + @NotNull TextRange range, + @NotNull String text, + boolean canBeMatched) + { + super(parent, range.getStartOffset(), range.getEndOffset(), type, "SECTION", canBeMatched); + myText = text; + } + + @NotNull + @Override + public String getText() { + return myText; + } +} diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerSectionsTest.groovy b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerSectionsTest.groovy new file mode 100644 index 000000000000..68a1ed3e988f --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerSectionsTest.groovy @@ -0,0 +1,1026 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.codeStyle.arrangement + +import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Modifier.PRIVATE +import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Modifier.PUBLIC +import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.EntryType.FIELD +import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.EntryType.METHOD +import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.EntryType.CLASS +import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.EntryType.INTERFACE +import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.EntryType.ENUM + +class JavaRearrangerSectionsTest extends AbstractJavaRearrangerTest { + + void "test single section"() { + doTest( + initial: ''' +class MyClass +{ + // --- Public Methods --- + + public void test() {} + + // --- End Public Methods --- + + private int number; +}''', + expected: ''' +class MyClass +{ + private int number; + + // --- Public Methods --- + public void test() {} + // --- End Public Methods --- +}''', + rules: [ + rule(FIELD), + section("// --- Public Methods ---", "// --- End Public Methods ---", rule(METHOD))] + ) + } + + void "test multi section"() { + doTest( + initial: ''' +class MyClass +{ + // --- Private Methods --- + + private void foo() {} + + // --- End Private Methods --- + + // --- Public Methods --- + + public void test() {} + + // --- End Public Methods --- + + public int p; +}''', + expected: ''' +class MyClass +{ + public int p; + + // --- Public Methods --- + public void test() {} + // --- End Public Methods --- + + // --- Private Methods --- + private void foo() {} + // --- End Private Methods --- +}''', + rules: [ + section(rule(FIELD)), + section("// --- Public Methods ---", "// --- End Public Methods ---", rule(PUBLIC, METHOD)), + section("// --- Private Methods ---", "// --- End Private Methods ---", rule(PRIVATE, METHOD)) + ] + ) + } + + + void "test multi region"() { + doTest( + initial: ''' +class MyClass +{ + //region Private Methods + + private void foo() {} + + //endregion private + + //region Public Methods + + public void test() {} + + //endregion public + + public int p; +}''', + expected: ''' +class MyClass +{ + public int p; + + //region Public Methods + public void test() {} + //endregion public + + //region Private Methods + private void foo() {} + //endregion private +}''', + rules: [ + section(rule(FIELD)), + section("//region Public Methods", "//endregion public", rule(PUBLIC, METHOD)), + section("//region Private Methods", "//endregion private", rule(PRIVATE, METHOD))] + ) + } + + + void "test new single section"() { + doTest( + initial: ''' +class MyClass +{ + public void test() {} + + public int p; +}''', + expected: ''' +class MyClass +{ + public int p; + +// --- Public Methods --- + public void test() {} +// --- End Public Methods --- +}''', + rules: [ + section(rule(FIELD)), + section("// --- Public Methods ---", "// --- End Public Methods ---", rule(METHOD))] + ) + } + + + void "test all new multi section without comments"() { + doTest( + initial: ''' +class MyClass +{ + public void test() {} + + public int p; +}''', + expected: ''' +class MyClass +{ + public int p; + +// --- Public Methods --- + public void test() {} +// --- End Public Methods --- +}''', + rules: [ + section(rule(FIELD)), + section("// --- Public Methods ---", "// --- End Public Methods ---", rule(METHOD)) + ] + ) + } + + + void "test new multi section"() { + doTest( + initial: ''' +class MyClass +{ + public int p; + + public void test() {} +}''', + expected: ''' +class MyClass +{ +// --- Fields --- + public int p; +// --- Fields --- + +// --- Public Methods --- + public void test() {} +// --- End Public Methods --- +}''', + rules: [ + section("// --- Fields ---", "// --- Fields ---", rule(FIELD)), + section("// --- Public Methods ---", "// --- End Public Methods ---", rule(METHOD))] + ) + } + + + void "test new not arranged multi section"() { + doTest( + initial: ''' +class MyClass +{ + public void test() {} + + public int p; +}''', + expected: ''' +class MyClass +{ +// --- Fields --- + public int p; +// --- Fields --- + +// --- Public Methods --- + public void test() {} +// --- End Public Methods --- +}''', + rules: [ + section("// --- Fields ---", "// --- Fields ---", rule(FIELD)), + section("// --- Public Methods ---", "// --- End Public Methods ---", rule(METHOD)) + ] + ) + } + + void "test blank lines"() { + doTest( + initial: ''' +class MyClass +{ + // --- Public Methods --- + public void test() {} + // --- End Public Methods --- + + public int p; +}''', + expected: ''' +class MyClass +{ + public int p; + + // --- Public Methods --- + public void test() {} + // --- End Public Methods --- +}''', + rules: [ + rule(FIELD), + section("// --- Public Methods ---", "// --- End Public Methods ---", rule(METHOD))] + ) + } + + void "test multi rules in section"() { + doTest( + initial: ''' +class MyClass +{ + private void foo() { + System.out.println("Hellow!"); + } + + // --- Methods --- + public void test() {} + // --- End Methods --- + + public int p; +}''', + expected: ''' +class MyClass +{ + public int p; + + // --- Methods --- + public void test() {} + + private void foo() { + System.out.println("Hellow!"); + } + // --- End Methods --- +}''', + rules: [ + rule(FIELD), + section("// --- Methods ---", "// --- End Methods ---", rule(PUBLIC, METHOD), rule(PRIVATE, METHOD))] + ) + } + + void "test multi rules in new section"() { + doTest( + initial: ''' +class MyClass +{ + private int i; + + private void foo() { + System.out.println("Hellow!"); + } + + // --- Methods --- + public void test() {} + // --- End Methods --- + + public int p; +}''', + expected: ''' +class MyClass +{ +// --- Properties --- + public int p; + private int i; +// --- End Properties --- + + // --- Methods --- + public void test() {} + + private void foo() { + System.out.println("Hellow!"); + } + // --- End Methods --- +}''', + rules: [ + section("// --- Properties ---", "// --- End Properties ---", rule(PUBLIC, FIELD), rule(PRIVATE, FIELD)), + section("// --- Methods ---", "// --- End Methods ---", rule(PUBLIC, METHOD), rule(PRIVATE, METHOD))] + ) + } + + + void "test section without close comment"() { + doTest( + initial: ''' +class MyClass +{ + private void foo() { + System.out.println("Hellow!"); + } + + // --- Methods --- + public void test() {} + + public int p; +}''', + expected: ''' +class MyClass +{ + public int p; + + // --- Methods --- + public void test() {} + + private void foo() { + System.out.println("Hellow!"); + } +}''', + rules: [ + section(rule(FIELD)), + section("// --- Methods ---", null, rule(PUBLIC, METHOD), rule(PRIVATE, METHOD)) + ] + ) + } + + void "test new section without close comment"() { + doTest( + initial: ''' +class MyClass +{ + private void foo() { + System.out.println("Hellow!"); + } + + // --- Methods --- + public void test() {} + + public int p; +}''', + expected: ''' +class MyClass +{ +// --- Properties --- + public int p; + + // --- Methods --- + public void test() {} + + private void foo() { + System.out.println("Hellow!"); + } +}''', + rules: [ + section("// --- Properties ---", null, rule(FIELD)), + section("// --- Methods ---", null, rule(PUBLIC, METHOD), rule(PRIVATE, METHOD)) + ] + ) + } + + void "test new section in hierarchy"() { + doTest( + initial: ''' +class MyClass +{ + private void foo() { + System.out.println("Hellow!"); + } + public void test() {} +}''', + expected: ''' +//region --- Class --- +class MyClass +{ +//region --- Methods --- + public void test() {} + + private void foo() { + System.out.println("Hellow!"); + } +//endregion methods +} +//endregion class''', + rules: [ + section("//region --- Class ---", "//endregion class", rule(CLASS)), + section("//region --- Methods ---", "//endregion methods", rule(PUBLIC, METHOD), rule(PRIVATE, METHOD)) + ] + ) + } + + void "test new sections in hierarchy"() { + doTest( + initial: ''' +interface MyI { +} + +class MyClass +{ + private void foo() { + System.out.println("Hellow!"); + } + public void test() {} +}''', + expected: ''' +//region --- Class --- +class MyClass +{ +//region --- Methods --- + public void test() {} + + private void foo() { + System.out.println("Hellow!"); + } +//endregion methods +} + +interface MyI { +} +//endregion class''', + rules: [ + section("//region --- Class ---", "//endregion class", rule(CLASS), rule(INTERFACE)), + section("//region --- Methods ---", "//endregion methods", rule(PUBLIC, METHOD), rule(PRIVATE, METHOD))] + ) + } + + void "test two methods section comments in a row"() { + doTest( + initial:''' +public class SuperTest { + //publicS + public void test() { + } +//publicE +//privateS + private void testPrivate() { + } +//privateE + + public int t; +} +''', + expected:''' +public class SuperTest { + public int t; + + //publicS + public void test() { + } +//publicE + +//privateS + private void testPrivate() { + } +//privateE +} +''', + rules: [ + rule(FIELD), + section("//publicS", "//publicE", rule(PUBLIC, METHOD)), + section("//privateS", "//privateE", rule(PRIVATE, METHOD)) + ] + ); + } + + void "test two fields section comments in a row"() { + doTest( + initial:''' +public class SuperTest { + public void test() {} + + //publicFieldStart + public int test = 2; +//publicFieldEnd +//privateFieldStart + private int pr = 1; +//privateFieldEnd +} +''', + expected:''' +public class SuperTest { + //publicFieldStart + public int test = 2; +//publicFieldEnd +//privateFieldStart + private int pr = 1; +//privateFieldEnd + + public void test() {} +} +''', + rules: [ + section("//publicFieldStart", "//publicFieldEnd", rule(PUBLIC, FIELD)), + section("//privateFieldStart", "//privateFieldEnd", rule(PRIVATE, FIELD)), + rule(METHOD) + ] + ); + } + + void "test no additional sections added"() { + doTest( + initial: ''' +//sectionClassStart +public class Test { +} +//sectionClassEnd +''', + expected: ''' +//sectionClassStart +public class Test { +} +//sectionClassEnd +''', + rules: [ + section("//sectionClassStart", "//sectionClassEnd", rule(CLASS)) + ] + ) + } + + void "test inner classes sections"() { + doTest( + initial: ''' +//sectionClassStart +public class Test { + + interface Testable { + } + +} +//sectionClassEnd +class Double { +} +''', + expected: ''' +//sectionClassStart +public class Test { + +//sectionInterfaceStart + interface Testable { + } +//sectionInterfaceEnd + +} + +class Double { +} +//sectionClassEnd +''', + rules: [ + section("//sectionClassStart", "//sectionClassEnd", rule(CLASS)), + section("//sectionInterfaceStart", "//sectionInterfaceEnd", rule(INTERFACE)) + ] + ) + } + + void "test a lot of sections"() { + def rules = [ + section("//sectionInterfaceStart", "//sectionInterfaceEnd", rule(INTERFACE)), + section("//sectionEnumStart", "//sectionEnumEnd", rule(ENUM)), + section("//sectionClassStart", "//sectionClassEnd", rule(CLASS)), + section("//sectionPublicFieldStart", "//sectionPublicFieldEnd", rule(FIELD, PUBLIC)), + section("//sectionPrivateFieldStart", "//sectionPrivateFieldEnd", rule(FIELD, PRIVATE)), + section("//sectionPubicMethodStart", "//sectionPublicMethodEnd", rule(METHOD, PUBLIC)), + section("//sectionPrivateMethodStart", "//sectionPrivateMethodEnd", rule(METHOD, PRIVATE)), + ] + + doTest( + initial: ''' +public class SuperTest { + + class T {} + + class R {} + + interface I {} + + enum Q {} + + public void test() {} + + private void teste2() {} + + public void testtt() {} + + public int a; + + private int b; +} + +class Test {} +''', + expected: ''' +//sectionClassStart +public class SuperTest { + +//sectionInterfaceStart + interface I {} +//sectionInterfaceEnd + +//sectionEnumStart + enum Q {} +//sectionEnumEnd + +//sectionClassStart + class T {} + + class R {} +//sectionClassEnd +//sectionPublicFieldStart + public int a; +//sectionPublicFieldEnd +//sectionPrivateFieldStart + private int b; +//sectionPrivateFieldEnd + +//sectionPubicMethodStart + public void test() {} + + public void testtt() {} +//sectionPublicMethodEnd + +//sectionPrivateMethodStart + private void teste2() {} +//sectionPrivateMethodEnd +} + +class Test {} +//sectionClassEnd +''', + rules: rules + ) + + doTest( + initial: ''' +//sectionClassStart +public class SuperTest { + +//sectionInterfaceStart + interface I {} +//sectionInterfaceEnd + +//sectionEnumStart + enum Q {} +//sectionEnumEnd + +//sectionClassStart + class T {} + + class R {} +//sectionClassEnd + +//sectionPublicFieldStart + public int a; +//sectionPublicFieldEnd + +//sectionPrivateFieldStart + private int b; +//sectionPrivateFieldEnd + +//sectionPubicMethodStart + public void test() {} + + public void testtt() {} +//sectionPublicMethodEnd + +//sectionPrivateMethodStart + private void teste2() {} +//sectionPrivateMethodEnd + + private void newPrivateTest() {} + + class NewClass {} + + interface NewInterface {} +} + +class Test {} +//sectionClassEnd + +class NewOuterClass {} +''', + expected: ''' +//sectionClassStart +public class SuperTest { + +//sectionInterfaceStart + interface I {} + interface NewInterface {} +//sectionInterfaceEnd +//sectionEnumStart + enum Q {} +//sectionEnumEnd + +//sectionClassStart + class T {} + + class R {} + + class NewClass {} +//sectionClassEnd +//sectionPublicFieldStart + public int a; +//sectionPublicFieldEnd +//sectionPrivateFieldStart + private int b; +//sectionPrivateFieldEnd + +//sectionPubicMethodStart + public void test() {} + + public void testtt() {} +//sectionPublicMethodEnd + +//sectionPrivateMethodStart + private void teste2() {} + + private void newPrivateTest() {} +//sectionPrivateMethodEnd +} + +class Test {} + +class NewOuterClass {} +//sectionClassEnd +''', + rules: rules + ) + } + + void "test range rearrangement"() { + doTest( + initial: ''' +public class Test { + //pubMS + public void test1() {} + private void test2() {} + public void test3() {} + //pubME + + //privMS + private void test4() {} + //privME +} +''', + expected: ''' +public class Test { + //pubMS + public void test1() {} + + public void test3() {} + //pubME + + //privMS + private void test2() {} + private void test4() {} + //privME +} +''', + rules: [ + section("//pubMS", "//pubME", rule(PUBLIC, METHOD)), + section("//privMS", "//privME", rule(PRIVATE, METHOD)) + ] + ) + } + + void "test on range with nested sections"() { + doTest( + initial: ''' +//classStart +public class Test { + + //classStart + class R {} + class T {} + public void test() {} + //classEnd + + //publicMethodStart + public void tester() {} + //publicMethodEnd +} + +class NewOne { +} +//classEnd +''', + expected: ''' +//classStart +public class Test { + + //classStart + class R {} + class T {} + //classEnd + + //publicMethodStart + public void test() {} + public void tester() {} + //publicMethodEnd +} + +class NewOne { +} +//classEnd +''', + rules: [ + section("//classStart", "//classEnd", rule(CLASS)), + section("//publicMethodStart", "//publicMethodEnd", rule(PUBLIC, METHOD)) + ] + ) + } + + //Now comes failing tests - to fix in future + + //TODO look at upper one - it succeeds this is not!!! + void "do not test on range with three inner sections"() { + doTest( + initial: ''' +//classStart +public class Test { + + //classStart + class R {} + class T {} + public void test() {} + //classEnd + + //fieldStart + public int i = 1; + //fieldEnd + + //publicMethodStart + public void tester() {} + //publicMethodEnd +} + +class NewOne { +} +//classEnd +''', + expected: ''' +//classStart +public class Test { + + //classStart + class R {} + class T {} + //classEnd + + //fieldStart + public int i = 1; + //fieldEnd + + //publicMethodStart + public void test() {} + public void tester() {} + //publicMethodEnd +} + +class NewOne { +} +//classEnd +''', + rules: [ + section("//classStart", "//classEnd", rule(CLASS)), + section("//fieldStart", "//fieldEnd", rule(FIELD)), + section("//publicMethodStart", "//publicMethodEnd", rule(PUBLIC, METHOD)) + ] + ) + } + + void "do not test field has not only section comments"() { + doTest( + initial: '''\ +class Test { + + //method start + //field1 + public int field1 = 1; + + //method end + + public void method test() {} + +} +''', + expected: '''\ +class Test { + + //field1 + public int field1 = 1; + + //method start + public void method test() {} + //method end + +} +''', + rules: [ + rule(FIELD), + section("//method start", "//method end", rule(METHOD)) + ] + ) + } + + + void "do not test class has not only section comments"() { + doTest( + initial: '''\ +//class start +//main class +public class Test { +} +//class end + +interface I { +} + +class A { +} + +class B { +} +''', + expected: '''\ +interface I { +} + +//class start +//main class +public class Test { +} + +class A { +} + +class B { +} +//class end +''', + rules: [ + rule(INTERFACE), + section("//class start", "//class end", rule(CLASS)) + ] + ) + } + + void "do not test method has not only section comments"() { + doTest( + initial: '''\ +class Test { + + //methods start + //first + public void test() {} + + private void t() {} + //method end +} +''', + expected: '''\ +class Test { + + //methods start + private void t() {} + + //first + public void test() {} + //method end + +} +''', + rules: [ + section("//methods start", "//method end", rule(PRIVATE, METHOD), rule(PUBLIC, METHOD)) + ] + ) + } + +}