}
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class InnerOuterRecordTest extends RefactoringTestBase {
+
+ public InnerOuterRecordTest(String name) {
+ super(name, "16");
+ //ensure we are running on at least 16.
+ try {
+ SourceVersion.valueOf("RELEASE_16"); //NOI18N
+ } catch (IllegalArgumentException ex) {
+ //OK, no RELEASE_16, skip test
+ throw new RuntimeException("need at least Java 16 for record");
+ }
+ sideBySideCompare = true;
+ showOutputOnPass=true;
+ }
+
+ public void test9ApacheNetbeans7044() throws Exception {
+ // initial outer has record with meaningful canonical constructor.
+ // note that Inner class should be in last member for assumptions in the test.
+ String source
+ = """
+ package t;
+
+ import java.time.LocalDate;
+ import java.util.Objects;
+
+ public class A {
+
+ void useStudent() {
+ F s = new F(42,"Jan Klaassen", LocalDate.now().minusDays(1));
+ System.out.println("student = " + s);
+ }
+ record F(int id, String name, LocalDate dob) {
+
+ /**
+ * Validate stuff.
+ */
+ public F {
+ Objects.requireNonNull(id);
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(dob);
+ assert !name.isEmpty() && !name.isBlank();
+ assert dob.isAfter(LocalDate.EPOCH);
+ }
+
+ public void method() {
+ }
+ }
+
+ }
+ """;
+ String newOuter
+ = """
+ package t;
+
+ import java.time.LocalDate;
+ import java.util.Objects;
+
+ public class A {
+
+ void useStudent() {
+ F s = new F(42,"Jan Klaassen", LocalDate.now().minusDays(1));
+ System.out.println("student = " + s);
+ }
+
+ }
+ """;
+ String newInner
+ = """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ import java.time.LocalDate;
+ import java.util.Objects;
+
+ /**
+ *
+ * @author junit
+ */
+ record F(int id, String name, LocalDate dob) {
+
+ /**
+ * Validate stuff.
+ */
+ public F {
+ Objects.requireNonNull(id);
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(dob);
+ assert !name.isEmpty() && !name.isBlank();
+ assert dob.isAfter(LocalDate.EPOCH);
+ }
+
+ public void method() {
+ }
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ public void test1BasicClassInClass() throws Exception {
+ // initial outer has record with meaningful canonical constructor.
+ String source
+ = """
+ package t;
+ import java.time.LocalDate;
+ import java.util.Objects;
+ public class A {
+ void useStudent() {
+ F s = new F(42, "Jan Klaassen", LocalDate.now().minusDays(1));
+ System.out.println("student = " + s);
+ }
+ public static class F {
+ int id;
+ String name;
+ LocalDate dob
+ public Student(int id, String name, LocalDate dob) {
+ Objects.requireNonNull(id);
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(dob);
+ assert !name.isEmpty() && !name.isBlank();
+ assert dob.isAfter(LocalDate.EPOCH);
+ this.id=id;
+ this.name=name;
+ this.dob=dob;
+ }
+ }
+ }
+ """;
+ String newOuter
+ = """
+ package t;
+ import java.time.LocalDate;
+ import java.util.Objects;
+ public class A {
+ void useStudent() {
+ F s = new F(42, "Jan Klaassen", LocalDate.now().minusDays(1));
+ System.out.println("student = " + s);
+ }
+ }
+ """;
+ String newInner
+ = """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ import java.time.LocalDate;
+ import java.util.Objects;
+
+ /**
+ *
+ * @author junit
+ */
+ public class F {
+
+ int id;
+ String name;
+ LocalDate dob;
+
+ public F(int id, String name, LocalDate dob) {
+ Objects.requireNonNull(id);
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(dob);
+ assert !name.isEmpty() && !name.isBlank();
+ assert dob.isAfter(LocalDate.EPOCH);
+ this.id = id;
+ this.name = name;
+ this.dob = dob;
+ }
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ public void test2BasicRecordInRecord() throws Exception {
+ String source
+ = """
+ package t;
+ import java.time.LocalDate;
+ record A(int id, String name, LocalDate dob) {
+ static F f;
+ record F(int x, int y){
+ /** I should be back. */
+ static String code = "nix";
+ }
+ }
+ """;
+ String newOuter
+ =
+ """
+ package t;
+ import java.time.LocalDate;
+ record A(int id, String name, LocalDate dob) {
+ static F f;
+ }
+ """;
+ String newInner
+ = """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ /**
+ *
+ * @author hom
+ */
+ record F(int x, int y) {
+ /** I should be back. */
+ static String code = "nix";
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ /**
+ * Test to verify what happens to the compact constructor in the outer
+ * record. It appears to survive the refactoring.
+ *
+ * @throws Exception
+ */
+ public void test3OuterWithCompact() throws Exception {
+ String source
+ = """
+ package t;
+
+ import java.time.LocalDate;
+
+ /** Record with compact ctor. */
+ record A(F f) {
+ public A{
+ assert f!=null;
+ }
+ record F(int id, String name, LocalDate dob){}
+
+ }
+ """;
+ String newOuter
+ = """
+ package t;
+
+ import java.time.LocalDate;
+
+ /** Record with compact ctor. */
+ record A(F f) {
+ public A{
+ assert f!=null;
+ }
+
+ }
+ """;
+ String newInner
+ = """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ import java.time.LocalDate;
+
+ /**
+ *
+ * @author junit
+ */
+ record F(int id, String name, LocalDate dob) {}
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ public void test4InnerWithCompact() throws Exception {
+ String source
+ = """
+ package t;
+ import java.time.LocalDate;
+ record A(F f) {
+ public A {
+ assert f != null;
+ }
+ record F(int id, String name, LocalDate dob) {
+ public F {
+ if (dob.isBefore(LocalDate.EPOCH)) {
+ throw new IllegalArgumentException("to old " + dob);
+ }
+ }
+ }
+ }
+ """;
+ String newOuter
+ = """
+ package t;
+ import java.time.LocalDate;
+ record A(F f) {
+ public A {
+ assert f != null;
+ }
+ }
+ """;
+ String newInner
+ = """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ import java.time.LocalDate;
+
+ /**
+ *
+ * @author junit
+ */
+ record F(int id, String name, LocalDate dob) {
+
+ public F {
+ if (dob.isBefore(LocalDate.EPOCH)) {
+ throw new IllegalArgumentException("to old " + dob);
+ }
+ }
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ // outer may have effect
+ public void test5ClassWithInnerRecord() throws Exception {
+ String source
+ = """
+ package t;
+
+ import java.time.LocalDate;
+
+ class A {
+
+ final F f;
+ public A(F f) {
+ assert f != null;
+ this.f=f;
+ }
+ record F(int id, String name, LocalDate dob) {
+ public F {
+ if (dob.isBefore(LocalDate.EPOCH)) {
+ throw new IllegalArgumentException("to old " + dob);
+ }
+ }
+ }
+
+ }
+ """;
+ String newOuter
+ = """
+ package t;
+
+ import java.time.LocalDate;
+
+ class A {
+
+ final F f;
+ public A(F f) {
+ assert f != null;
+ this.f=f;
+ }
+
+ }
+ """;
+ String newInner
+ = """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ import java.time.LocalDate;
+
+ /**
+ *
+ * @author junit
+ */
+ record F(int id, String name, LocalDate dob) {
+
+ public F {
+ if (dob.isBefore(LocalDate.EPOCH)) {
+ throw new IllegalArgumentException("to old " + dob);
+ }
+ }
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ public void test6InnerWithCompactAndMethodAndExtraCtor() throws Exception {
+ AssertLinesEqualHelpers.setStringCompareMode(StringsCompareMode.IGNORE_WHITESPACE_DIFF);
+ String source
+ = """
+ package t;
+
+ import java.time.LocalDate;
+
+ record A(F f) {
+
+ enum Suite {
+ SPADE, CLUB, DIAMOND, HEART;
+ }
+
+ public A {
+ assert f != null;
+ }
+
+ record F(int id, String name, LocalDate dob) {
+
+ public F {
+ if (dob.isBefore(LocalDate.EPOCH)) {
+ throw new IllegalArgumentException("to old " + dob);
+ }
+ }
+
+ public F(int id, String name){
+ this(id,name,LocalDate.now());
+ }
+
+ boolean bornBefore(LocalDate someDate) {
+ return dob.isBefore(someDate);
+ }
+
+ }
+
+ }
+ """;
+ String newOuter
+ = """
+ package t;
+
+ import java.time.LocalDate;
+
+ record A(F f) {
+
+ enum Suite {
+ SPADE, CLUB, DIAMOND, HEART;
+ }
+
+ public A {
+ assert f != null;
+ }
+
+ }
+ """;
+ String newInner
+ = """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ import java.time.LocalDate;
+
+ /**
+ *
+ * @author junit
+ */
+ record F(int id, String name, LocalDate dob) {
+
+ public F {
+ if (dob.isBefore(LocalDate.EPOCH)) {
+ throw new IllegalArgumentException("to old " + dob);
+ }
+ }
+
+ public F(int id, String name) {
+ this(id, name, LocalDate.now());
+ }
+
+ boolean bornBefore(LocalDate someDate) {
+ return dob.isBefore(someDate);
+ }
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ public void test7Generic() throws Exception {
+ AssertLinesEqualHelpers.setStringCompareMode(StringsCompareMode.IGNORE_WHITESPACE_DIFF);
+ String source
+ = """
+ package t;
+ record A(F f) {
+ public A {
+ assert f != null;
+ }
+ record F> (P first, Q second) {
+ public F {
+ assert null != first;
+ assert null != second;
+ }
+
+ @Override
+ public int compare(Q o){
+ return this.second.compareTo(o.second);
+ }
+ }
+ }
+ """;
+ String newOuter
+ = """
+ package t;
+ record A(F f) {
+ public A {
+ assert f != null;
+ }
+ }
+ """;
+ String newInner
+ = """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ /**
+ *
+ * @author junit
+ */
+ record F
>(P first, Q second) {
+ public F {
+ assert null != first;
+ assert null != second;
+ }
+
+ @Override
+ public int compare(Q o) {
+ return this.second.compareTo(o.second);
+ }
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ // disable for the time being, varargs not yet implemented
+ public void test8Varargs() throws Exception {
+ AssertLinesEqualHelpers.setStringCompareMode(StringsCompareMode.IGNORE_INDENTATION);
+ String source =
+ """
+ package t;
+ record A(F f, String... params) {
+ public A {
+ assert f != null;
+ }
+ record F
(P first, String... second) {
+ public F {
+ assert null != first;
+ assert null != second && second.length > 0;
+ }
+ }
+ }
+ """;
+ String newOuter =
+ """
+ package t;
+ record A(F f, String... params) {
+ public A {
+ assert f != null;
+ }
+ }
+ """;
+ String newInner =
+ """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ /**
+ *
+ * @author junit
+ */
+ record F
(P first, String... second) {
+ public F {
+ assert null != first;
+ assert null != second && second.length > 0;
+ }
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ // disable for the time being, varargs not yet implemented
+ public void test8VarargsWithGen() throws Exception {
+ String source =
+ """
+ package t;
+ record A(F f, Q... params) {
+ public A {
+ assert f != null;
+ }
+ record F(P first, P... second) {
+ public F {
+ assert null != first;
+ assert null != second && second.length > 0;
+ }
+ }
+ }
+ """;
+ String newOuter =
+ """
+ package t;
+ record A(F f, Q... params) {
+ public A {
+ assert f != null;
+ }
+ }
+ """;
+ String newInner =
+ """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ /**
+ *
+ * @author junit
+ */
+ record F(P first, P... second) {
+
+ public F {
+ assert null != first;
+ assert null != second && second.length > 0;
+ }
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ // show that brace comes too early in inner record.
+ public void test8RecordImplements1() throws Exception {
+ sideBySideCompare = true;
+ String source
+ = """
+ package t;
+ import java.time.LocalDate;
+ import java.io.Serializable;
+ public class A implements Cloneable, Serializable {
+ static F f;
+ public record F(int x, int y) implements Cloneable, Serializable {
+ /** I should be back. */
+ static String code = "nix";
+ }
+ }
+ """;
+ String newOuter
+ = """
+ package t;
+ import java.time.LocalDate;
+ import java.io.Serializable;
+ public class A implements Cloneable, Serializable {
+ static F f;
+ }
+ """;
+ String newInner
+ = """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ import java.io.Serializable;
+
+ /**
+ *
+ * @author hom
+ */
+ public record F(int x, int y) implements Cloneable, Serializable {
+ /** I should be back. */
+ static String code = "nix";
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ // show that outer record survives casual diff.
+ public void test8RecordImplements2() throws Exception {
+ sideBySideCompare = true;
+ String source
+ = """
+ package t;
+ import java.time.LocalDate;
+ import java.io.Serializable;
+ public record A(int a, String b) implements Cloneable, Serializable {
+ static F f;
+ enum F {
+ F1, F2;
+ /** I should be back. */
+ static String code = "nix";
+ }
+ }
+ """;
+ String newOuter
+ = """
+ package t;
+ import java.time.LocalDate;
+ import java.io.Serializable;
+ public record A(int a, String b) implements Cloneable, Serializable {
+ static F f;
+ }
+ """;
+ String newInner
+ =
+ """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ /**
+ *
+ * @author hom
+ */
+ enum F {
+
+ F1, F2;
+ /** I should be back. */
+ static String code = "nix";
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ // Test shows that inner enum does not have the too early brace problem.
+ public void test8EnumImplements() throws Exception {
+ sideBySideCompare = true;
+ String source
+ = """
+ package t;
+ import java.time.LocalDate;
+ import java.io.Serializable;
+ public class A implements Cloneable, Serializable {
+ static F f;
+ enum F implements Cloneable, Serializable {
+ F1,F2;
+ /** I should be back. */
+ static String code = "nix";
+ }
+ }
+ """;
+ String newOuter
+ = """
+ package t;
+ import java.time.LocalDate;
+ import java.io.Serializable;
+ public class A implements Cloneable, Serializable {
+ static F f;
+ }
+ """;
+ String newInner
+ =
+ """
+ /*
+ * Refactoring License
+ */
+
+ package t;
+
+ import java.io.Serializable;
+
+ /**
+ *
+ * @author hom
+ */
+ enum F implements Cloneable, Serializable {
+
+ F1, F2;
+ /** I should be back. */
+ static String code = "nix";
+
+ }
+ """;
+ innerOuterSetupAndTest(source, newOuter, newInner);
+ }
+
+ void innerOuterSetupAndTest(String source, String newOuterText, String newInnerText) throws Exception {
+ writeFilesNoIndexing(src, new File("t/A.java", source));
+ performInnerToOuterTest2(null);
+ verifyContent(src, new File("t/A.java", newOuterText), new File("t/F.java", newInnerText));
+ }
+ boolean debug = false;
+
+ // variant for record inner to outer test
+ private void performInnerToOuterTest2(String newOuterName, Problem... expectedProblems) throws Exception {
+ final InnerToOuterRefactoring[] r = new InnerToOuterRefactoring[1];
+ JavaSource.forFileObject(src.getFileObject("t/A.java")).runUserActionTask(new Task() {
+ @Override
+ public void run(CompilationController parameter) {
+ try {
+ parameter.toPhase(JavaSource.Phase.RESOLVED);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ CompilationUnitTree cut = parameter.getCompilationUnit();
+ if (debug) {
+ System.err.println("cut is of type " + cut.getClass().getCanonicalName());
+ }
+ ClassTree outer = (ClassTree) cut.getTypeDecls().get(0);
+ if (debug) {
+ printNumbered(System.err, "start source " + outer.getKind().toString(), outer.toString());
+ }
+ List extends Tree> members = outer.getMembers();
+ int m = 0;
+ if (debug) {
+ printMembers(members, m);
+ }
+ // selecting the last element assumes that the inner class is the last member in the outer class.
+ Tree lastInnerClass
+ = outer.getMembers().get(outer.getMembers().size() - 1);
+ if (debug && lastInnerClass instanceof ClassTree lct) {
+// String n = "lastInnerClass " + lastInnerClass.getKind().toString();
+// printNumbered(System.err, n, lastInnerClass.toString());
+ printClassTree(lct);
+ }
+ TreePath tp = TreePath.getPath(cut, lastInnerClass);
+ try {
+ r[0]
+ = new InnerToOuterRefactoring(TreePathHandle.create(tp, parameter));
+ } catch (Throwable t) {
+ System.err.println("InnerOuter refatoring failed with exception " + t);
+ t.printStackTrace(System.out);
+ throw t;
+ }
+ }
+ }, true);
+ r[0].setClassName("F");
+ if (debug) {
+ printNumbered(System.err, "result ", r[0].toString());
+ }
+ r[0].setReferenceName(newOuterName);
+ RefactoringSession rs = RefactoringSession.create("Session");
+ List problems = new LinkedList();
+ addAllProblems(problems, r[0].preCheck());
+ addAllProblems(problems, r[0].prepare(rs));
+ addAllProblems(problems, rs.doRefactoring(true));
+ assertProblems(Arrays.asList(expectedProblems), problems);
+ }
+
+ // test helper
+ static void printMembers(List extends Tree> members, int m) {
+ printMembers(members, m, "");
+ }
+
+ // test helper
+ static void printMembers(List extends Tree> members, int m, String indent) {
+ for (Tree member : members) {
+ printNumbered(System.err, indent + "member %d %15s".formatted(m, member.getKind()), member.toString());
+ String toString = member.toString();
+ if (member instanceof ClassTree ct) {
+ int n = 0;
+ Name simpleName = ct.getSimpleName();
+ List extends Tree> members1 = ct.getMembers();
+ printMembers(members1, n, indent + " " + m + " ");
+ }
+ m++;
+ }
+ }
+
+ // test helper
+ static void printClassTree(ClassTree ct) {
+ printMembers(ct.getMembers(), 0, "class " + ct.getSimpleName() + " type " + ct.getKind() + " ");
+ }
+}
diff --git a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/PullUpTest.java b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/PullUpTest.java
index fb7cde7eda01..815a60858b85 100644
--- a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/PullUpTest.java
+++ b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/PullUpTest.java
@@ -34,6 +34,8 @@
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.Task;
import org.netbeans.api.java.source.TreePathHandle;
+import org.netbeans.junit.AssertLinesEqualHelpers;
+import static org.netbeans.junit.AssertLinesEqualHelpers.*;
import org.netbeans.modules.java.source.parsing.JavacParser;
import org.netbeans.modules.refactoring.api.Problem;
import org.netbeans.modules.refactoring.api.RefactoringSession;
@@ -52,11 +54,11 @@ public class PullUpTest extends RefactoringTestBase {
public PullUpTest(String name) {
super(name, "1.8");
}
-
+
static {
JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;
}
-
+
public void test241514a() throws Exception {
writeFilesAndWaitForScan(src,
new File("pullup/A.java", "package pullup; public interface A { void x(); }"),
@@ -66,7 +68,7 @@ public void test241514a() throws Exception {
new File("pullup/A.java", "package pullup; public interface A { void x(); void y(); }"),
new File("pullup/B.java", "package pullup; public interface B extends A { default void y() { } }"));
}
-
+
public void test241514b() throws Exception {
writeFilesAndWaitForScan(src,
new File("pullup/A.java", "package pullup; public interface A { void x(); }"),
@@ -76,7 +78,7 @@ public void test241514b() throws Exception {
new File("pullup/A.java", "package pullup; public interface A { void x(); default void y() { } }"),
new File("pullup/B.java", "package pullup; public interface B extends A {}"));
}
-
+
public void testPullUpOverridingMethod() throws Exception {
writeFilesAndWaitForScan(src,
new File("pullup/A.java", "package pullup; public class A extends B implements C { @Override public void i() { } }"),
@@ -87,7 +89,7 @@ public void testPullUpOverridingMethod() throws Exception {
new File("pullup/A.java", "package pullup; public class A extends B implements C {}"),
new File("pullup/B.java", "package pullup; public class B { public void i() { } }"),
new File("pullup/C.java", "package pullup; public interface C { void i(); }"));
-
+
writeFilesAndWaitForScan(src,
new File("pullup/A.java", "package pullup; public class A extends B { @Override public void i() { } }"),
new File("pullup/B.java", "package pullup; public class B extends C { }"),
@@ -98,7 +100,7 @@ public void testPullUpOverridingMethod() throws Exception {
new File("pullup/B.java", "package pullup; public class B extends C { @Override public void i() { } }"),
new File("pullup/C.java", "package pullup; public class C { public void i() { } }"));
}
-
+
public void test230719() throws Exception {
writeFilesAndWaitForScan(src,
new File("pullup/A.java", "package pullup; public interface A {\n"
@@ -127,14 +129,14 @@ public void test230719() throws Exception {
+ " }\n"
+ "}"));
}
-
+
public void test230930() throws Exception {
writeFilesAndWaitForScan(src,
new File("pullup/A.java", "package pullup; public interface A { }"),
new File("pullup/B.java", "package pullup; public class B implements A { static void y(); }"));
performPullUpIface(src.getFileObject("pullup/B.java"), 0, 0, true);
}
-
+
public void test229061() throws Exception {
writeFilesAndWaitForScan(src,
new File("pullup/A.java", "package pullup; public interface A { void x(); }"),
@@ -154,7 +156,7 @@ public void test134034() throws Exception {
new File("pullup/A.java", "package pullup; public class A { void x() { } void y() { x(); } }"),
new File("pullup/B.java", "package pullup; public class B extends A {}"));
}
-
+
public void test212934() throws Exception {
writeFilesAndWaitForScan(src,
new File("pullup/A.java", "package pullup; public class A { }"),
@@ -181,7 +183,7 @@ public void testPullUpField() throws Exception {
new File("pullup/A.java", "package pullup; public class A extends B {}"),
new File("pullup/B.java", "package pullup; public class B { public int i; }"));
}
-
+
public void testPullUpGenMethoda() throws Exception { // #147508 - [Pull Up][Push down] Remap generic names
writeFilesAndWaitForScan(src,
new File("pullup/PullUpBaseClass.java", "package pullup;\n"
@@ -303,7 +305,7 @@ public void testPullUpGenMethodb() throws Exception {
new File("pullup/B.java", "package pullup; public class B extends C { }"),
new File("pullup/C.java", "package pullup; public class C { void method(String x) { } }"));
}
-
+
public void testPullUpGenMethodc() throws Exception {
writeFilesAndWaitForScan(src,
new File("pullup/A.java", "package pullup; public class A extends B { X method() { } }"),
@@ -325,7 +327,7 @@ public void testPullUpGenMethodc() throws Exception {
new File("pullup/B.java", "package pullup; public class B extends C { }"),
new File("pullup/C.java", "package pullup; public class C { void method(String x) { } }"));
}
-
+
public void testPullUpGenField() throws Exception {
writeFilesAndWaitForScan(src,
new File("pullup/A.java", "package pullup; public class A extends B { X x; }"),
@@ -447,7 +449,7 @@ public void testPullUpMethod() throws Exception {
+ "\n"
+ "}"));
}
-
+
public void testPullUpMethodUndo() throws Exception {
writeFilesAndWaitForScan(src,
new File("pullup/PullUpBaseClass.java", "package pullup;\n"
@@ -1166,7 +1168,7 @@ public void testPullUpInterface() throws Exception {
new File("pullup/A.java", "package pullup; public class A extends B { public void run() { } }"),
new File("pullup/B.java", "package pullup; public class B implements Runnable { }"));
}
-
+
public void testPullUpInterface2() throws Exception {
writeFilesAndWaitForScan(src,
new File("pullup/A.java", "package pullup; public class A implements B { }"),
@@ -1206,6 +1208,247 @@ public void testPullUpLocalyReferenced() throws Exception {
new File("pullup/B.java", "package pullup; public class B { protected void foo() { } }"));
}
+ public void testPullUpInnerTypeEnum() throws Exception {
+
+ writeFilesAndWaitForScan(src,
+ new File("pullup/A.java",
+ """
+ package pullup;
+ public class A extends B {
+ private void foo() {
+ }
+ enum Suite implements I{ Heart, Diamond, Club, Spade; }
+ private void method(Suite s) {
+ foo();
+ }
+ }"""
+ ),
+ new File("pullup/B.java",
+ """
+ package pullup;
+ public class B { }
+ """
+ ),
+ new File("pullup/I.java",
+ """
+ package pullup;
+ public interface I{ }
+ """
+ )
+ );
+ performPullUp(src.getFileObject("pullup/A.java"), 2, Boolean.FALSE);
+ verifyContent(src,
+ new File("pullup/A.java",
+ """
+ package pullup;
+ public class A extends B {
+ private void foo() {
+ }
+ private void method(Suite s) {
+ foo();
+ }
+ }"""
+ ),
+ new File("pullup/B.java",
+ """
+ package pullup;
+ public class B {
+
+ enum Suite implements I {
+ Heart, Diamond, Club, Spade
+ }
+ }
+ """
+ ) ,
+ new File("pullup/I.java",
+ """
+ package pullup;
+ public interface I{ }
+ """
+ )
+
+ );
+ }
+
+ public void testPullUpInnerSimpleRecord() throws Exception {
+ sideBySideCompare=true;
+ showOutputOnPass=true;
+ setStringCompareMode(StringsCompareMode.IGNORE_INDENTATION);
+ writeFilesAndWaitForScan(src,
+ new File("pullup/A.java",
+ """
+ package pullup;
+ public class A extends B {
+ record R( int i, String name ) {}
+ private void foo() {
+ }
+ private void method(R r) {
+ foo();
+ }
+ }"""
+ ),
+ new File("pullup/B.java",
+ """
+ package pullup;
+ public class B { }
+ """
+ ),
+ new File("pullup/I.java",
+ """
+ package pullup;
+ public interface I{ }
+ """
+ )
+ );
+ performPullUp(src.getFileObject("pullup/A.java"), 1, Boolean.FALSE);
+ verifyContent(src,
+ new File("pullup/A.java",
+ """
+ package pullup;
+ public class A extends B {
+ private void foo() {
+ }
+ private void method(R r) {
+ foo();
+ }
+ }"""
+ ),
+ new File("pullup/B.java",
+ """
+ package pullup;
+ public class B {
+
+ record R(int i, String name) {
+ }
+ }
+ """
+ ) ,
+ new File("pullup/I.java",
+ """
+ package pullup;
+ public interface I{ }
+ """
+ )
+
+ );
+ }
+
+ public void testPullUpVarargRecord() throws Exception {
+ sideBySideCompare = true;
+ showOutputOnPass = true;
+ setStringCompareMode(StringsCompareMode.IGNORE_INDENTATION);
+
+ writeFilesAndWaitForScan(src,
+ new File("pullup/A.java",
+ """
+ package pullup;
+ public class A extends B {
+ record R( int i, String... name ) {}
+ private void foo() {
+ }
+ private void method(R r) {
+ foo();
+ }
+ }"""
+ ),
+ new File("pullup/B.java",
+ """
+ package pullup;
+ public class B { }
+ """
+ ),
+ new File("pullup/I.java",
+ """
+ package pullup;
+ public interface I{ }
+ """
+ )
+ );
+ performPullUp(src.getFileObject("pullup/A.java"), 1, Boolean.FALSE);
+ verifyContent(src,
+ new File("pullup/A.java",
+ """
+ package pullup;
+ public class A extends B {
+ private void foo() {
+ }
+ private void method(R r) {
+ foo();
+ }
+ }"""
+ ),
+ new File("pullup/B.java",
+ """
+ package pullup;
+ public class B {
+
+ record R(int i, String... name) {
+ }
+ }
+ """
+ ) ,
+ new File("pullup/I.java",
+ """
+ package pullup;
+ public interface I{ }
+ """
+ )
+
+ );
+ }
+
+ // disable because implements part is broken
+ public void testPullUpInnerRecord() throws Exception {
+ sideBySideCompare=true;
+ writeFilesAndWaitForScan(src,
+ new File("pullup/A.java",
+ """
+ package pullup;
+ public class A extends B {
+ record R( int age, String name ) {}
+ private void foo() {
+ }
+ private void method(R r) {
+ foo();
+ }
+ }
+ """
+ ),
+ new File("pullup/B.java",
+ """
+ package pullup;
+ public class B {}
+ """
+ )
+ );
+ String asText = src.getFileObject("pullup/A.java").asText();
+// System.out.println("asText = " + asText);
+ performPullUp(src.getFileObject("pullup/A.java"), 1, Boolean.FALSE);
+ verifyContent(src,
+ new File("pullup/A.java",
+ """
+ package pullup;
+ public class A extends B {
+ private void foo() {
+ }
+ private void method(R r) {
+ foo();
+ }
+ }"""
+ ),
+ new File("pullup/B.java",
+ """
+ package pullup;
+ public class B {
+
+ record R(int age, String name) {
+ }
+ }
+ """
+ )
+ );
+ }
+
private void performPullUpImplements(FileObject source, final int position, final int supertype, Problem... expectedProblems) throws IOException, IllegalArgumentException, InterruptedException {
final PullUpRefactoring[] r = new PullUpRefactoring[1];
JavaSource.forFileObject(source).runUserActionTask(new Task() {
diff --git a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RefactoringTestBase.java b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RefactoringTestBase.java
index ebc261b08126..fe7feca8c65a 100644
--- a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RefactoringTestBase.java
+++ b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RefactoringTestBase.java
@@ -21,7 +21,9 @@
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.PrintStream;
import java.nio.charset.Charset;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -31,6 +33,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.ChangeListener;
@@ -46,6 +49,7 @@
import org.netbeans.api.project.Sources;
import org.netbeans.core.startup.Main;
import org.netbeans.junit.NbTestCase;
+import static org.netbeans.junit.AssertLinesEqualHelpers.*;
import org.netbeans.modules.java.source.BootClassPathUtil;
import org.netbeans.modules.java.source.TestUtil;
import org.netbeans.modules.java.source.indexing.JavaCustomIndexer;
@@ -75,8 +79,7 @@
public class RefactoringTestBase extends NbTestCase {
public RefactoringTestBase(String name) {
- super(name);
- sourcelevel = "1.6";
+ this(name,"17");
}
public RefactoringTestBase(String name, String sourcelevel) {
@@ -84,7 +87,38 @@ public RefactoringTestBase(String name, String sourcelevel) {
this.sourcelevel = sourcelevel;
}
+ static boolean debug = false;
+// static boolean skipIndexing = false;
+
+ /**
+ * Write given files to sourceRoot and fully re index.
+ *
+ * First the (file) children of sourceRoot are deleted. This method can take
+ * a substantial time of your patience, so use wisely. See the doc in
+ * {@link IndexManager#refreshIndexAndWait}
+ *
+ * @param sourceRoot sic
+ * @param files to save
+ * @throws Exception whenever
+ */
protected static void writeFilesAndWaitForScan(FileObject sourceRoot, File... files) throws Exception {
+ writeFilesAndWaitForScan(true, sourceRoot, files);
+ }
+
+ /**
+ * Write given files to sourceRoot and possibly reindex.
+ *
+ * First the (file) children of sourceRoot are deleted. This method can take
+ * a substantial time of your patience, so use wisely. See the doc in
+ * {@link IndexManager#refreshIndexAndWait}
+ *
+ * @param fulleIndex fully reindex the type repo
+ * @param sourceRoot sic
+ * @param files to save
+ * @throws Exception whenever
+ */
+ protected static void writeFilesAndWaitForScan(boolean fullIndex, FileObject sourceRoot, File... files) throws Exception {
+ long currentTimeMillis = System.currentTimeMillis();
for (FileObject c : sourceRoot.getChildren()) {
c.delete();
}
@@ -94,9 +128,38 @@ protected static void writeFilesAndWaitForScan(FileObject sourceRoot, File... fi
TestUtilities.copyStringToFile(fo, f.content);
}
- IndexingManager.getDefault().refreshIndexAndWait(sourceRoot.toURL(), null, true);
+ if (fullIndex) {
+ IndexingManager.getDefault().refreshIndexAndWait(sourceRoot.toURL(), null, true);
+ long currentTimeMillis1 = System.currentTimeMillis();
+ if (debug) {
+ System.err.println("writeFilesAndWaitForScan took " + (currentTimeMillis1 - currentTimeMillis) + " millis");
+ }
+ }
}
+ /**
+ * Save file but do not reindex.
+ *
+ * Deletes the existing files under sourceRoot, then saves the given files.
+ *
+ * Makes tests run faster. In particular single tests.
+ *
+ * @param sourceRoot sic
+ * @param files to save
+ * @throws Exception whenever
+ */
+ protected static void writeFilesNoIndexing(FileObject sourceRoot, File... files) throws Exception {
+ writeFilesAndWaitForScan(false, sourceRoot, files);
+ }
+
+ /**
+ * Verify that the given file(names) are present in the sourceRoot and that
+ * the files in said sourceRoot are equal to the given files.
+ *
+ * @param sourceRoot to contain generated (refactored) files
+ * @param files expected files
+ * @throws Exception well why not?
+ */
protected void verifyContent(FileObject sourceRoot, File... files) throws Exception {
List todo = new LinkedList();
@@ -109,33 +172,41 @@ protected void verifyContent(FileObject sourceRoot, File... files) throws Except
while (!todo.isEmpty()) {
FileObject file = todo.remove(0);
- if (file.isData()) {
+ if (file.isData()) { // normal file
content.put(FileUtil.getRelativePath(sourceRoot, file), copyFileToString(FileUtil.toFile(file)));
- } else {
+ } else { // it is a folder
todo.addAll(Arrays.asList(file.getChildren()));
}
}
+ List exc = new ArrayList<>();
for (File f : files) {
- String fileContent = content.remove(f.filename);
-
- assertNotNull(f);
- assertNotNull(f.content);
- assertNotNull("Cannot find " + f.filename + " in map " + content, fileContent);
+ // take the element from the map filled by sourceRootTraversal.
try {
- assertEquals(getName() ,f.content.replaceAll("[ \t\r\n\n]+", " "), fileContent.replaceAll("[ \t\r\n\n]+", " "));
- } catch (Throwable t) {
- System.err.println("expected:");
- System.err.println(f.content);
- System.err.println("actual:");
- System.err.println(fileContent);
- throw t;
+ String fileContent = content.remove(f.filename);
+ assertNotNull(f);
+ assertNotNull(f.content);
+ assertNotNull("Cannot find expected " + f.filename + " in map filled by sourceRoot " + content, fileContent);
+ if (sideBySideCompare) {
+ assertLinesEqual2(getName(),f.filename, f.content, fileContent);
+ } else { // original tests.
+ assertLinesEqual1(f.filename, f.content, fileContent);
+ }
+ } catch (AssertionError | Exception t) {
+ exc.add(t);
}
}
+ if (exc.size() > 0) {
+ Throwable x = exc.get(0);
+ if (x instanceof AssertionError ae) throw ae;
+ throw (Exception) x;
+ }
- assertTrue(content.toString(), content.isEmpty());
+ assertTrue("not all files processeed", content.isEmpty());
}
-
+
+ protected boolean sideBySideCompare = false;
+
/**
* Returns a string which contains the contents of a file.
*
@@ -167,14 +238,14 @@ protected static void assertProblems(Iterable extends Problem> golden, Iterabl
Problem gp = g.next();
Problem rp = r.next();
- assertEquals(gp.isFatal(), rp.isFatal());
- assertEquals(gp.getMessage(), rp.getMessage());
+ assertEquals("fatality differs",gp.isFatal(), rp.isFatal());
+ assertEquals("expected message differs", gp.getMessage(), rp.getMessage());
}
boolean goldenHasNext = g.hasNext();
boolean realHasNext = r.hasNext();
- assertFalse(goldenHasNext?"Expected: " + g.next().getMessage():"", goldenHasNext);
- assertFalse(realHasNext?"Unexpected: " + r.next().getMessage():"", realHasNext);
+ assertFalse(goldenHasNext ? "Expected: " + g.next().getMessage() : "", goldenHasNext);
+ assertFalse(realHasNext ? "Unexpected: " + r.next().getMessage() : "", realHasNext);
}
static {
@@ -182,6 +253,7 @@ protected static void assertProblems(Iterable extends Problem> golden, Iterabl
}
protected static final class File {
+
public final String filename;
public final String content;
@@ -202,144 +274,147 @@ protected void setUp() throws Exception {
System.setProperty("org.netbeans.modules.java.source.usages.SourceAnalyser.fullIndex", "true");
Logger.getLogger("").setLevel(Level.SEVERE); //turn off chatty logs
MimeTypes.setAllMimeTypes(new HashSet());
- SourceUtilsTestUtil.prepareTest(new String[] {"org/netbeans/modules/openide/loaders/layer.xml",
- "org/netbeans/modules/java/source/resources/layer.xml",
- "org/netbeans/modules/java/editor/resources/layer.xml",
- "org/netbeans/modules/refactoring/java/test/resources/layer.xml", "META-INF/generated-layer.xml"}, new Object[] {
- new ClassPathProvider() {
- @Override
- public ClassPath findClassPath(FileObject file, String type) {
- if (sourcePath != null && sourcePath.contains(file)){
- if (ClassPath.BOOT.equals(type)) {
- return TestUtil.getBootClassPath();
- }
- if (JavaClassPathConstants.MODULE_BOOT_PATH.equals(type)) {
- return BootClassPathUtil.getModuleBootPath();
- }
- if (ClassPath.COMPILE.equals(type)) {
- return ClassPathSupport.createClassPath(new FileObject[0]);
- }
- if (ClassPath.SOURCE.equals(type)) {
- return sourcePath;
- }
- }
-
- return null;
+ SourceUtilsTestUtil.prepareTest(new String[]{"org/netbeans/modules/openide/loaders/layer.xml",
+ "org/netbeans/modules/java/source/resources/layer.xml",
+ "org/netbeans/modules/java/editor/resources/layer.xml",
+ "org/netbeans/modules/refactoring/java/test/resources/layer.xml", "META-INF/generated-layer.xml"}, new Object[]{
+ new ClassPathProvider() {
+ @Override
+ public ClassPath findClassPath(FileObject file, String type) {
+ if (sourcePath != null && sourcePath.contains(file)) {
+ if (ClassPath.BOOT.equals(type)) {
+ return TestUtil.getBootClassPath();
}
- },
- new ProjectFactory() {
- @Override
- public boolean isProject(FileObject projectDirectory) {
- return src != null && src.getParent() == projectDirectory;
+ if (JavaClassPathConstants.MODULE_BOOT_PATH.equals(type)) {
+ return BootClassPathUtil.getModuleBootPath();
}
- @Override
- public Project loadProject(final FileObject projectDirectory, ProjectState state) throws IOException {
- if (!isProject(projectDirectory)) {
+ if (ClassPath.COMPILE.equals(type)) {
+ return ClassPathSupport.createClassPath(new FileObject[0]);
+ }
+ if (ClassPath.SOURCE.equals(type)) {
+ return sourcePath;
+ }
+ }
+
return null;
}
- return new Project() {
+ },
+ new ProjectFactory() {
+ @Override
+ public boolean isProject(FileObject projectDirectory) {
+ return src != null && src.getParent() == projectDirectory;
+ }
+
+ @Override
+ public Project loadProject(final FileObject projectDirectory, ProjectState state) throws IOException {
+ if (!isProject(projectDirectory)) {
+ return null;
+ }
+ return new Project() {
+ @Override
+ public FileObject getProjectDirectory() {
+ return projectDirectory;
+ }
+
+ @Override
+ public Lookup getLookup() {
+ final Project p = this;
+ return Lookups.singleton(new Sources() {
+
@Override
- public FileObject getProjectDirectory() {
- return projectDirectory;
+ public SourceGroup[] getSourceGroups(String type) {
+ return new SourceGroup[]{GenericSources.group(p, src.getParent(), "source", "Java Sources", null, null),
+ GenericSources.group(p, test, "testsources", "Test Sources", null, null)};
}
+
@Override
- public Lookup getLookup() {
- final Project p = this;
- return Lookups.singleton(new Sources() {
-
- @Override
- public SourceGroup[] getSourceGroups(String type) {
- return new SourceGroup[] {GenericSources.group(p, src.getParent(), "source", "Java Sources", null, null),
- GenericSources.group(p, test, "testsources", "Test Sources", null, null)};
- }
-
- @Override
- public void addChangeListener(ChangeListener listener) {
- }
-
- @Override
- public void removeChangeListener(ChangeListener listener) {
- }
- });
+ public void addChangeListener(ChangeListener listener) {
}
- };
- }
- @Override
- public void saveProject(Project project) throws IOException, ClassCastException {}
- },
- new TestLocator() {
- @Override
- public boolean appliesTo(FileObject fo) {
- return true;
+ @Override
+ public void removeChangeListener(ChangeListener listener) {
+ }
+ });
}
+ };
+ }
- @Override
- public boolean asynchronous() {
- return false;
- }
+ @Override
+ public void saveProject(Project project) throws IOException, ClassCastException {
+ }
+ },
+ new TestLocator() {
- @Override
- public LocationResult findOpposite(FileObject fo, int caretOffset) {
- ClassPath srcCp;
-
- if ((srcCp = ClassPath.getClassPath(fo, ClassPath.SOURCE)) == null) {
- return new LocationResult("File not found"); //NOI18N
- }
-
- String baseResName = srcCp.getResourceName(fo, '/', false);
- String testResName = getTestResName(baseResName, fo.getExt());
- assert testResName != null;
- FileObject fileObject = test.getFileObject(testResName);
- if(fileObject != null) {
- return new LocationResult(fileObject, -1);
- }
-
- return new LocationResult("File not found"); //NOI18N
- }
+ @Override
+ public boolean appliesTo(FileObject fo) {
+ return true;
+ }
- @Override
- public void findOpposite(FileObject fo, int caretOffset, LocationListener callback) {
- throw new UnsupportedOperationException("This should not be called on synchronous locators.");
- }
+ @Override
+ public boolean asynchronous() {
+ return false;
+ }
- @Override
- public FileType getFileType(FileObject fo) {
- if(FileUtil.isParentOf(test, fo)) {
- return FileType.TEST;
- } else if(FileUtil.isParentOf(src, fo)) {
- return FileType.TESTED;
- }
- return FileType.NEITHER;
- }
+ @Override
+ public LocationResult findOpposite(FileObject fo, int caretOffset) {
+ ClassPath srcCp;
- private String getTestResName(String baseResName, String ext) {
- StringBuilder buf
- = new StringBuilder(baseResName.length() + ext.length() + 10);
- buf.append(baseResName).append("Test"); //NOI18N
- if (ext.length() != 0) {
- buf.append('.').append(ext);
- }
- return buf.toString();
- }
- },
- new SourceLevelQueryImplementation() {
+ if ((srcCp = ClassPath.getClassPath(fo, ClassPath.SOURCE)) == null) {
+ return new LocationResult("File not found"); //NOI18N
+ }
- @Override
- public String getSourceLevel(FileObject javaFile) {
- return sourcelevel;
- }
- }});
+ String baseResName = srcCp.getResourceName(fo, '/', false);
+ String testResName = getTestResName(baseResName, fo.getExt());
+ assert testResName != null;
+ FileObject fileObject = test.getFileObject(testResName);
+ if (fileObject != null) {
+ return new LocationResult(fileObject, -1);
+ }
+
+ return new LocationResult("File not found"); //NOI18N
+ }
+
+ @Override
+ public void findOpposite(FileObject fo, int caretOffset, LocationListener callback) {
+ throw new UnsupportedOperationException("This should not be called on synchronous locators.");
+ }
+
+ @Override
+ public FileType getFileType(FileObject fo) {
+ if (FileUtil.isParentOf(test, fo)) {
+ return FileType.TEST;
+ } else if (FileUtil.isParentOf(src, fo)) {
+ return FileType.TESTED;
+ }
+ return FileType.NEITHER;
+ }
+
+ private String getTestResName(String baseResName, String ext) {
+ StringBuilder buf
+ = new StringBuilder(baseResName.length() + ext.length() + 10);
+ buf.append(baseResName).append("Test"); //NOI18N
+ if (ext.length() != 0) {
+ buf.append('.').append(ext);
+ }
+ return buf.toString();
+ }
+ },
+ new SourceLevelQueryImplementation() {
+
+ @Override
+ public String getSourceLevel(FileObject javaFile) {
+ return sourcelevel;
+ }
+ }});
Main.initializeURLFactory();
org.netbeans.api.project.ui.OpenProjects.getDefault().getOpenProjects();
-
+
// org.netbeans.modules.java.source.TreeLoader.DISABLE_CONFINEMENT_TEST = true;
-
prepareTest();
- org.netbeans.api.project.ui.OpenProjects.getDefault().open(new Project[] {prj = ProjectManager.getDefault().findProject(src.getParent())}, false);
+ org.netbeans.api.project.ui.OpenProjects.getDefault().open(new Project[]{prj = ProjectManager.getDefault().findProject(src.getParent())}, false);
MimeTypes.setAllMimeTypes(Collections.singleton("text/x-java"));
sourcePath = ClassPathSupport.createClassPath(src, test);
- GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, new ClassPath[] {sourcePath});
+ GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, new ClassPath[]{sourcePath});
RepositoryUpdater.getDefault().start(true);
super.setUp();
FileUtil.createData(FileUtil.getConfigRoot(), "Templates/Classes/Empty.java");
@@ -349,8 +424,8 @@ public String getSourceLevel(FileObject javaFile) {
@Override
protected void tearDown() throws Exception {
super.tearDown();
- GlobalPathRegistry.getDefault().unregister(ClassPath.SOURCE, new ClassPath[] {sourcePath});
- org.netbeans.api.project.ui.OpenProjects.getDefault().close(new Project[] {prj});
+ GlobalPathRegistry.getDefault().unregister(ClassPath.SOURCE, new ClassPath[]{sourcePath});
+ org.netbeans.api.project.ui.OpenProjects.getDefault().close(new Project[]{prj});
CountDownLatch cdl = new CountDownLatch(1);
RepositoryUpdater.getDefault().stop(() -> {
cdl.countDown();
@@ -366,12 +441,12 @@ private void prepareTest() throws Exception {
src = FileUtil.createFolder(projectFolder, "src");
test = FileUtil.createFolder(projectFolder, "test");
- FileObject cache = FileUtil.createFolder(workdir, "cache");
+ FileObject cache = FileUtil.createFolder(workdir, "cache");
- CacheFolder.setCacheFolder(cache);
- }
+ CacheFolder.setCacheFolder(cache);
+ }
- @ServiceProvider(service=MimeDataProvider.class)
+ @ServiceProvider(service = MimeDataProvider.class)
public static final class MimeDataProviderImpl implements MimeDataProvider {
private static final Lookup L = Lookups.singleton(new JavaCustomIndexer.Factory());
@@ -384,7 +459,7 @@ public Lookup getLookup(MimePath mimePath) {
return null;
}
-
+
}
protected static boolean problemIsFatal(List problems) {
@@ -400,7 +475,7 @@ protected static boolean problemIsFatal(List problems) {
return false;
}
- private static final int RETRIES = 3;
+ protected int RETRIES = 3;
@Override
protected void runTest() throws Throwable {
@@ -411,10 +486,13 @@ protected void runTest() throws Throwable {
super.runTest();
return;
} catch (Throwable t) {
- if (exc == null) exc = t;
+ if (exc == null) {
+ exc = t;
+ }
}
}
- throw exc;
+ if (exc != null) {
+ throw exc;
+ }
}
-
-}
\ No newline at end of file
+}
diff --git a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RenameRecordTest.java b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RenameRecordTest.java
index 43fbba7faa72..2b950bcc5d55 100644
--- a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RenameRecordTest.java
+++ b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/RenameRecordTest.java
@@ -29,6 +29,7 @@
import org.netbeans.api.java.source.TestUtilities;
import org.netbeans.api.java.source.TestUtilities.TestInput;
import org.netbeans.api.java.source.TreePathHandle;
+import static org.netbeans.junit.AssertLinesEqualHelpers.*;
import org.netbeans.modules.refactoring.api.Problem;
import org.netbeans.modules.refactoring.api.RefactoringSession;
import org.netbeans.modules.refactoring.api.RenameRefactoring;
@@ -40,13 +41,53 @@ public class RenameRecordTest extends RefactoringTestBase {
public RenameRecordTest(String name) {
super(name, "17");
+ sideBySideCompare=true;
+ showOutputOnPass=true;
}
public void testRenameComponent1() throws Exception {
String testCode = """
- package test;
- public record Test(int compo|nent) {}
- """;
+ package test;
+ public record Test(int compo|nent, int y) {}
+ """;
+ TestInput splitCode = TestUtilities.splitCodeAndPos(testCode);
+ writeFilesAndWaitForScan(src,
+ new File("Test.java", splitCode.code()),
+ new File("Use.java",
+ """
+ package test;
+ public class Use {
+ private void test(Test t) {
+ int i = t.component();
+ }
+ }
+ """));
+ JavaRenameProperties props = new JavaRenameProperties();
+ performRename(src.getFileObject("Test.java"), splitCode.pos(), "newName", props, true);
+ verifyContent(src, new File("Test.java",
+ """
+ package test;
+ public record Test(int newName, int y) {}
+ """),
+ new File("Use.java",
+ """
+ package test;
+ public class Use {
+ private void test(Test t) {
+ int i = t.newName();
+ }
+ }
+ """));
+
+ }
+
+ // changes in refactoring or javs.source.base breaks rename
+ // when there is somthing before the 'com|ponent'.
+ public void testRenameComponent1a() throws Exception {
+ String testCode = """
+ package test;
+ public record Test(int x, int compo|nent) {}
+ """;
TestInput splitCode = TestUtilities.splitCodeAndPos(testCode);
writeFilesAndWaitForScan(src,
new File("Test.java", splitCode.code()),
@@ -64,7 +105,7 @@ private void test(Test t) {
verifyContent(src, new File("Test.java",
"""
package test;
- public record Test(int newName) {}
+ public record Test(int x, int newName) {}
"""),
new File("Use.java",
"""
@@ -78,21 +119,64 @@ private void test(Test t) {
}
+ // disabled, somehow having int x before to be renamed component
+ // breaks list diff
+ public void testRenameComponent1b() throws Exception {
+ String testCode = """
+ package test;
+ public record Test(int x, int compo|nent) {}
+ """;
+ TestInput splitCode = TestUtilities.splitCodeAndPos(testCode);
+ writeFilesAndWaitForScan(src,
+ new File("Test.java", splitCode.code()),
+ new File("Use.java",
+ """
+ package test;
+ public class Use {
+ private void test(Test t) {
+ int i = t.component();
+ }
+ }
+ """));
+ JavaRenameProperties props = new JavaRenameProperties();
+ performRename(src.getFileObject("Test.java"), splitCode.pos(), "newName", props, true);
+ verifyContent(src, new File("Test.java",
+ """
+ package test;
+ public record Test(int x, int newName) {}
+ """),
+ new File("Use.java",
+ """
+ package test;
+ public class Use {
+ private void test(Test t) {
+ int i = t.newName();
+ }
+ }
+ """));
+
+ }
+
+ // this test has an explicit accessor.
+ // this appears to break on potential compact constructor not being compact.
public void testRenameComponent2() throws Exception {
String testCode = """
- package test;
- public record Test(int compo|nent) {
- public Test(int component) {
- component = -1;
- }
- public int component() {
- return component;
- }
- public int hashCode() {
- return component;
- }
- }
- """;
+ package test;
+ public record Test(int compo|nent, int y) {
+ public Test {
+ component = -1;
+ }
+ public int component() {
+ return component;
+ }
+ public int hashCode() {
+ return component;
+ }
+ public Test(int someInt) {
+ this(someInt, 0);
+ }
+ }
+ """;
TestInput splitCode = TestUtilities.splitCodeAndPos(testCode);
writeFilesAndWaitForScan(src,
new File("Test.java", splitCode.code()),
@@ -110,8 +194,8 @@ private void test(Test t) {
verifyContent(src, new File("Test.java",
"""
package test;
- public record Test(int newName) {
- public Test(int newName) {
+ public record Test(int newName, int y) {
+ public Test {
newName = -1;
}
public int newName() {
@@ -120,6 +204,9 @@ public int newName() {
public int hashCode() {
return newName;
}
+ public Test(int someInt) {
+ this(someInt, 0);
+ }
}
"""),
new File("Use.java",
@@ -134,11 +221,14 @@ private void test(Test t) {
}
+ /*
+ * Show that with compact constructor behaves.
+ */
public void testRenameComponent3() throws Exception {
String testCode = """
package test;
- public record Test(int compo|nent) {
- public Test {
+ public record Test(int compo|nent, int y) {
+ public Test { //compact
component = -1;
}
public int component() {
@@ -166,8 +256,8 @@ private void test(Test t) {
verifyContent(src, new File("Test.java",
"""
package test;
- public record Test(int newName) {
- public Test {
+ public record Test(int newName, int y) {
+ public Test { //compact
newName = -1;
}
public int newName() {
@@ -204,7 +294,7 @@ private void test(Test t) {
new File("Test.java",
"""
package test;
- public record Test(int component) {
+ public record Test(int component, int y) {
public Test {
component = -1;
}
@@ -222,7 +312,7 @@ public int hashCode() {
verifyContent(src, new File("Test.java",
"""
package test;
- public record Test(int newName) {
+ public record Test(int newName, int y) {
public Test {
newName = -1;
}
@@ -260,7 +350,7 @@ private void test(Test t) {
new File("Test.java",
"""
package test;
- public record Test(int component) {
+ public record Test(int component, int y) {
}
"""),
new File("Use.java", splitCode.code()));
@@ -269,7 +359,7 @@ public record Test(int component) {
verifyContent(src, new File("Test.java",
"""
package test;
- public record Test(int newName) {
+ public record Test(int newName, int y) {
}
"""),
new File("Use.java",
@@ -287,7 +377,7 @@ private void test(Test t) {
public void testRenameComponentStartFromConstructorArg() throws Exception {
String testCode = """
package test;
- public record Test(int component) {
+ public record Test(int component, int y) {
public Test {
compo|nent = -1;
}
@@ -316,7 +406,7 @@ private void test(Test t) {
verifyContent(src, new File("Test.java",
"""
package test;
- public record Test(int newName) {
+ public record Test(int newName, int y) {
public Test {
newName = -1;
}
@@ -382,6 +472,102 @@ private NewName test() {
"""));
}
+
+ // test for varargs and generic.
+ public void testRenameRecordGenVar() throws Exception {
+ sideBySideCompare=true;
+ showOutputOnPass=true;
+
+ String testCode = """
+ package test;
+ public record Te|st(G... component) {
+ public Test {
+ assert 0 < component.length;
+ }
+ }
+ """;
+ TestInput splitCode = TestUtilities.splitCodeAndPos(testCode);
+ writeFilesAndWaitForScan(src,
+ new File("Test.java", splitCode.code()),
+ new File("Use.java",
+ """
+ package test;
+ public class Use {
+ private Test test() {
+ return new Test(1, 2);
+ }
+ }
+ """));
+ JavaRenameProperties props = new JavaRenameProperties();
+ performRename(src.getFileObject("Test.java"), splitCode.pos(), "NewName", props, true);
+ verifyContent(src, new File("Test.java",
+ """
+ package test;
+ public record NewName(G... component) {
+ public NewName {
+ assert 0 < component.length;
+ }
+ }
+ """),
+ new File("Use.java",
+ """
+ package test;
+ public class Use {
+ private NewName test() {
+ return new NewName(1, 2);
+ }
+ }
+ """));
+
+ }
+ // test for varargs and generic.
+ public void testRenameRecordGenVarComponent() throws Exception {
+ sideBySideCompare=true;
+ showOutputOnPass=true;
+
+ String testCode = """
+ package test;
+ public record Test(G... comp|onent) {
+ public Test {
+ assert 0 < component.length;
+ }
+ }
+ """;
+ TestInput splitCode = TestUtilities.splitCodeAndPos(testCode);
+ writeFilesAndWaitForScan(src,
+ new File("Test.java", splitCode.code()),
+ new File("Use.java",
+ """
+ package test;
+ public class Use {
+ private Test test() {
+ return new Test(1, 2);
+ }
+ }
+ """));
+ JavaRenameProperties props = new JavaRenameProperties();
+ performRename(src.getFileObject("Test.java"), splitCode.pos(), "parts", props, true);
+ verifyContent(src, new File("Test.java",
+ """
+ package test;
+ public record Test(G... parts) {
+ public Test {
+ assert 0 < parts.length;
+ }
+ }
+ """),
+ new File("Use.java",
+ """
+ package test;
+ public class Use {
+ private Test test() {
+ return new Test(1, 2);
+ }
+ }
+ """));
+
+ }
+
private void performRename(FileObject source, final int absPos, final String newname, final JavaRenameProperties props, final boolean searchInComments, Problem... expectedProblems) throws Exception {
final RenameRefactoring[] r = new RenameRefactoring[1];
JavaSource.forFileObject(source).runUserActionTask(new Task() {