diff --git a/.gitignore b/.gitignore index ec10551..c3cddb8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target/ +.gradle/ .idea/ *.iml diff --git a/src/main/java/com/seleniumboot/migrator/Analyzer.java b/src/main/java/com/seleniumboot/migrator/Analyzer.java index 56f76ca..7772430 100644 --- a/src/main/java/com/seleniumboot/migrator/Analyzer.java +++ b/src/main/java/com/seleniumboot/migrator/Analyzer.java @@ -58,8 +58,9 @@ public Report analyze(Path root) throws IOException { parsed++; scan(result.getResult().get(), root.relativize(f).toString(), findings, locatorStats); } - return new Report(files.size(), parsed, unparsable, findings, - BuildFileAnalyzer.detect(root), locatorStats.counts()); + List detectedTechnologies = BuildFileAnalyzer.detect(root); + return new Report(files.size(), parsed, unparsable, findings, detectedTechnologies, + recognizedTechnologies(detectedTechnologies), locatorStats.counts()); } /** Analyze a single pasted source string. */ @@ -71,7 +72,7 @@ public Report analyzeSource(String source) { return new Report(1, 0, List.of(""), findings); } scan(result.getResult().get(), "", findings, locatorStats); - return new Report(1, 1, List.of(), findings, List.of(), locatorStats.counts()); + return new Report(1, 1, List.of(), findings, List.of(), List.of(), locatorStats.counts()); } private void scan(CompilationUnit cu, String file, List out, LocatorStats locatorStats) { @@ -235,4 +236,53 @@ private static boolean isWebDriverType(String type) { private static boolean isAnnotation(String name, String simpleName) { return name.equals(simpleName) || name.endsWith("." + simpleName); } + + private static List recognizedTechnologies(List detectedTechnologies) { + boolean testNg = false; + boolean junit4 = false; + boolean junit5 = false; + boolean webDriverManager = false; + boolean extentReports = false; + boolean allure = false; + String seleniumVersion = null; + + for (String detected : detectedTechnologies) { + if (!detected.startsWith("Dependency: ")) continue; + + String[] coordinates = detected.substring("Dependency: ".length()).split(":", -1); + if (coordinates.length < 2) continue; + + String groupId = coordinates[0]; + String artifactId = coordinates[1]; + String version = coordinates.length > 2 ? coordinates[2] : ""; + + if (groupId.equals("org.seleniumhq.selenium") && artifactId.equals("selenium-java")) { + seleniumVersion = version; + } else if (groupId.equals("org.testng") && artifactId.equals("testng")) { + testNg = true; + } else if (groupId.equals("junit") && artifactId.equals("junit")) { + junit4 = true; + } else if (groupId.equals("org.junit.jupiter")) { + junit5 = true; + } else if (groupId.equals("io.github.bonigarcia") && artifactId.equals("webdrivermanager")) { + webDriverManager = true; + } else if (groupId.equals("com.aventstack") && artifactId.equals("extentreports")) { + extentReports = true; + } else if (groupId.equals("io.qameta.allure")) { + allure = true; + } + } + + List recognized = new ArrayList<>(); + if (seleniumVersion != null) { + recognized.add(seleniumVersion.isBlank() ? "Selenium" : "Selenium " + seleniumVersion); + } + if (testNg) recognized.add("TestNG"); + if (junit4) recognized.add("JUnit 4"); + if (junit5) recognized.add("JUnit 5"); + if (webDriverManager) recognized.add("WebDriverManager"); + if (extentReports) recognized.add("ExtentReports"); + if (allure) recognized.add("Allure"); + return List.copyOf(recognized); + } } diff --git a/src/main/java/com/seleniumboot/migrator/Report.java b/src/main/java/com/seleniumboot/migrator/Report.java index 183faa2..c331125 100644 --- a/src/main/java/com/seleniumboot/migrator/Report.java +++ b/src/main/java/com/seleniumboot/migrator/Report.java @@ -5,15 +5,16 @@ import java.util.TreeMap; public record Report(int filesFound, int filesParsed, List unparsable, List findings, - List detectedTechnologies, Map locatorCounts) { + List detectedTechnologies, List recognizedTechnologies, + Map locatorCounts) { public Report(int filesFound, int filesParsed, List unparsable, List findings) { - this(filesFound, filesParsed, unparsable, findings, List.of(), Map.of()); + this(filesFound, filesParsed, unparsable, findings, List.of(), List.of(), Map.of()); } public Report(int filesFound, int filesParsed, List unparsable, List findings, List detectedTechnologies) { - this(filesFound, filesParsed, unparsable, findings, detectedTechnologies, Map.of()); + this(filesFound, filesParsed, unparsable, findings, detectedTechnologies, List.of(), Map.of()); } public long count(Finding.Status s) { @@ -58,6 +59,12 @@ public String render() { } else { detectedTechnologies.forEach(technology -> sb.append(" ").append(technology).append('\n')); } + sb.append("\nRecognized technologies\n"); + if (recognizedTechnologies.isEmpty()) { + sb.append(" No supported test technologies detected\n"); + } else { + sb.append(" ").append(String.join(", ", recognizedTechnologies)).append('\n'); + } sb.append("\nLocator usage:\n"); if (locatorCounts.isEmpty()) { sb.append(" None detected\n"); diff --git a/src/test/java/com/seleniumboot/migrator/AnalyzerTest.java b/src/test/java/com/seleniumboot/migrator/AnalyzerTest.java index 1222d48..d8d3600 100644 --- a/src/test/java/com/seleniumboot/migrator/AnalyzerTest.java +++ b/src/test/java/com/seleniumboot/migrator/AnalyzerTest.java @@ -191,6 +191,125 @@ void ignoresBuildFilesInGeneratedAndVendorDirectories(@TempDir Path root) throws assertTrue(output.contains("No supported build descriptor found")); } + @Test + void detectsMavenAndTechnologies() throws Exception { + Path temp = Files.createTempDirectory("selenium-test"); + + Files.writeString(temp.resolve("pom.xml"), """ + + + + org.seleniumhq.selenium + selenium-java + 4.20.0 + + + org.testng + testng + 7.10.0 + + + org.junit.jupiter + junit-jupiter + 5.10.2 + + + junit + junit + 4.13.2 + + + io.github.bonigarcia + webdrivermanager + 5.8.0 + + + com.aventstack + extentreports + 5.1.1 + + + io.qameta.allure + allure-testng + 2.27.0 + + + + """); + + var report = new Analyzer().analyze(temp); + + assertTrue(report.render().contains("Maven")); + assertTrue(report.render().contains("Selenium 4.20.0")); + assertTrue(report.render().contains("TestNG")); + assertTrue(report.render().contains("JUnit 5")); + assertTrue(report.render().contains("WebDriverManager")); + assertEquals(List.of("Selenium 4.20.0", "TestNG", "JUnit 4", "JUnit 5", + "WebDriverManager", "ExtentReports", "Allure"), report.recognizedTechnologies()); + } + + @Test + void recognizesOnlyDirectDependenciesAndDeduplicatesModules(@TempDir Path root) throws Exception { + Files.writeString(root.resolve("pom.xml"), """ + + + + + org.junit.jupiter + junit-jupiter + 5.10.2 + + + + + + org.testng + testng + 7.10.0 + + + + + + + + com.aventstack + extentreports + 5.1.1 + + + + + + + """); + + Path module = Files.createDirectories(root.resolve("module")); + Files.writeString(module.resolve("pom.xml"), """ + + + + org.testng + testng + 7.10.0 + + + org.seleniumhq.selenium + selenium-java + 4.20.0 + + + + """); + + var report = new Analyzer().analyze(root); + + assertEquals(List.of("Selenium 4.20.0", "TestNG"), report.recognizedTechnologies()); + assertEquals(1, report.detectedTechnologies().stream() + .filter(dependency -> dependency.equals("Dependency: org.testng:testng:7.10.0")) + .count()); + } + @Test void allAutoFindingsHaveFullConfidence() { var report = new Analyzer().analyzeSource(""" @@ -261,6 +380,37 @@ void waitForElement() { .count()); } + @Test + void rejectsDoctypeInMavenBuildFile(@TempDir Path root) throws Exception { + Path secret = Files.writeString(root.resolve("external.txt"), "must-not-be-read"); + Files.writeString(root.resolve("pom.xml"), """ + ]> + + + + org.testng + testng + &xxe; + + + + """.formatted(secret.toUri())); + + String output = new Analyzer().analyze(root).render(); + + assertTrue(output.contains("Build system: Maven (could not parse pom.xml)")); + assertFalse(output.contains("must-not-be-read")); + } + + @Test + void missingPomIsNotDetected() throws Exception { + Path temp = Files.createTempDirectory("selenium-test"); + + var report = new Analyzer().analyze(temp); + + assertTrue(report.render().contains("No supported build descriptor found")); + } + @Test void countsSeleniumLocatorUsageAndKeepsFullConfidence() { var report = new Analyzer().analyzeSource("""