diff --git a/settings.gradle.kts b/settings.gradle.kts index ef60d8bf9..9609b1644 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,6 +30,7 @@ include(":testng-reflection-utils") include(":testng-runner-api") include(":testng-test-kit") include(":testng-test-osgi") +include(":testng-jaxb") enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") diff --git a/testng-core/testng-core-build.gradle.kts b/testng-core/testng-core-build.gradle.kts index 873187f5e..defc19026 100644 --- a/testng-core/testng-core-build.gradle.kts +++ b/testng-core/testng-core-build.gradle.kts @@ -28,6 +28,7 @@ tasks.withType().configureEach { dependencies { api(projects.testngCoreApi) + implementation("jakarta.xml.bind:jakarta.xml.bind-api:4.0.2") // Annotations have to be available on the compile classpath for the proper compilation compileOnly("com.github.spotbugs:spotbugs:4.8.1") api("org.jcommander:jcommander:1.83") diff --git a/testng-jaxb/src/main/java/org/testng/xml/jaxb/JaxbParser.java b/testng-jaxb/src/main/java/org/testng/xml/jaxb/JaxbParser.java new file mode 100644 index 000000000..ec694a66d --- /dev/null +++ b/testng-jaxb/src/main/java/org/testng/xml/jaxb/JaxbParser.java @@ -0,0 +1,27 @@ +package org.testng.xml.jaxb; + +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import java.io.InputStream; +import org.testng.xml.ISuiteParser; +import org.testng.xml.XmlSuite; +import org.testng.xml.jaxb.mappers.SuiteMapper; + +public class JaxbParser implements ISuiteParser { + + @Override + public XmlSuite parse(String filePath, InputStream is, boolean loadClasses) { + try { + JAXBContext jaxbContext = JAXBContext.newInstance(Suite.class); + Suite suite = (Suite) jaxbContext.createUnmarshaller().unmarshal(is); + return SuiteMapper.toXmlSuite(suite); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean accept(String fileName) { + return fileName.endsWith(".xml"); + } +} diff --git a/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/ListenersMapper.java b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/ListenersMapper.java new file mode 100644 index 000000000..7130cefd7 --- /dev/null +++ b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/ListenersMapper.java @@ -0,0 +1,15 @@ +package org.testng.xml.jaxb.mappers; + +import java.util.List; +import java.util.stream.Collectors; +import org.testng.xml.jaxb.Listener; +import org.testng.xml.jaxb.Listeners; + +public class ListenersMapper { + + public static List toXmlListeners(Listeners listeners) { + return listeners.getListener().stream() + .map(Listener::getClassName) + .collect(Collectors.toList()); + } +} diff --git a/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/MethodSelectorsMapper.java b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/MethodSelectorsMapper.java new file mode 100644 index 000000000..d0b166ca1 --- /dev/null +++ b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/MethodSelectorsMapper.java @@ -0,0 +1,29 @@ +package org.testng.xml.jaxb.mappers; + +import java.util.List; +import java.util.stream.Collectors; +import org.testng.xml.XmlMethodSelector; +import org.testng.xml.jaxb.MethodSelectors; +import org.testng.xml.jaxb.Script; +import org.testng.xml.jaxb.SelectorClass; + +public class MethodSelectorsMapper { + + public static List toXmlMethodSelectors(MethodSelectors methodSelectors) { + return methodSelectors.getMethodSelector().stream() + .map( + ms -> { + XmlMethodSelector xmlMethodSelector = new XmlMethodSelector(); + if (ms.getScript() != null) { + Script script = ms.getScript(); + xmlMethodSelector.setScript(ScriptMapper.toXmlScript(script)); + } else if (ms.getSelectorClass() != null && !ms.getSelectorClass().isEmpty()) { + SelectorClass sc = ms.getSelectorClass().get(0); + xmlMethodSelector.setName(sc.getName()); + xmlMethodSelector.setPriority(Integer.parseInt(sc.getPriority())); + } + return xmlMethodSelector; + }) + .collect(Collectors.toList()); + } +} diff --git a/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/PackagesMapper.java b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/PackagesMapper.java new file mode 100644 index 000000000..3f7b87a91 --- /dev/null +++ b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/PackagesMapper.java @@ -0,0 +1,15 @@ +package org.testng.xml.jaxb.mappers; + +import java.util.List; +import java.util.stream.Collectors; +import org.testng.xml.XmlPackage; +import org.testng.xml.jaxb.Packages; + +public class PackagesMapper { + + public static List toXmlPackages(Packages packages) { + return packages.getPackage().stream() + .map(p -> new XmlPackage(p.getName())) + .collect(Collectors.toList()); + } +} diff --git a/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/ParameterMapper.java b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/ParameterMapper.java new file mode 100644 index 000000000..fbac20f37 --- /dev/null +++ b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/ParameterMapper.java @@ -0,0 +1,12 @@ +package org.testng.xml.jaxb.mappers; + +import java.util.Map; +import java.util.stream.Collectors; +import org.testng.xml.jaxb.Parameter; + +public class ParameterMapper { + + public static Map toXmlParameters(java.util.List parameters) { + return parameters.stream().collect(Collectors.toMap(Parameter::getName, Parameter::getValue)); + } +} diff --git a/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/ScriptMapper.java b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/ScriptMapper.java new file mode 100644 index 000000000..cad9213fb --- /dev/null +++ b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/ScriptMapper.java @@ -0,0 +1,16 @@ +package org.testng.xml.jaxb.mappers; + +import java.util.stream.Collectors; +import org.testng.xml.XmlScript; +import org.testng.xml.jaxb.Script; + +public class ScriptMapper { + + public static XmlScript toXmlScript(Script script) { + XmlScript xmlScript = new XmlScript(); + xmlScript.setLanguage(script.getLanguage()); + xmlScript.setExpression( + script.getContent().stream().map(Object::toString).collect(Collectors.joining())); + return xmlScript; + } +} diff --git a/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/SuiteFilesMapper.java b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/SuiteFilesMapper.java new file mode 100644 index 000000000..cef97ac91 --- /dev/null +++ b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/SuiteFilesMapper.java @@ -0,0 +1,13 @@ +package org.testng.xml.jaxb.mappers; + +import java.util.List; +import java.util.stream.Collectors; +import org.testng.xml.jaxb.SuiteFile; +import org.testng.xml.jaxb.SuiteFiles; + +public class SuiteFilesMapper { + + public static List toXmlSuiteFiles(SuiteFiles suiteFiles) { + return suiteFiles.getSuiteFile().stream().map(SuiteFile::getPath).collect(Collectors.toList()); + } +} diff --git a/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/SuiteMapper.java b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/SuiteMapper.java new file mode 100644 index 000000000..a1e147adc --- /dev/null +++ b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/SuiteMapper.java @@ -0,0 +1,59 @@ +package org.testng.xml.jaxb.mappers; + +import org.testng.xml.XmlSuite; +import org.testng.xml.jaxb.Suite; + +public class SuiteMapper { + + public static XmlSuite toXmlSuite(Suite suite) { + XmlSuite xmlSuite = new XmlSuite(); + xmlSuite.setName(suite.getName()); + if (suite.getVerbose() != null) { + xmlSuite.setVerbose(Integer.parseInt(suite.getVerbose())); + } + if (suite.getParallel() != null) { + xmlSuite.setParallel(XmlSuite.ParallelMode.getValidParallel(suite.getParallel())); + } + if (suite.getThreadCount() != null) { + xmlSuite.setThreadCount(Integer.parseInt(suite.getThreadCount())); + } + if (suite.getDataProviderThreadCount() != null) { + xmlSuite.setDataProviderThreadCount(Integer.parseInt(suite.getDataProviderThreadCount())); + } + if (suite.getConfigfailurepolicy() != null) { + xmlSuite.setConfigFailurePolicy( + XmlSuite.FailurePolicy.getValidPolicy(suite.getConfigfailurepolicy())); + } + if (suite.getGroupByInstances() != null) { + xmlSuite.setGroupByInstances(Boolean.parseBoolean(suite.getGroupByInstances())); + } + if (suite.getAllowReturnValues() != null) { + xmlSuite.setAllowReturnValues(Boolean.parseBoolean(suite.getAllowReturnValues())); + } + xmlSuite.setTimeOut(suite.getTimeOut()); + + for (Object o : suite.getListenersOrPackagesOrTest()) { + if (o instanceof org.testng.xml.jaxb.Listeners) { + xmlSuite.setListeners(ListenersMapper.toXmlListeners((org.testng.xml.jaxb.Listeners) o)); + } else if (o instanceof org.testng.xml.jaxb.Packages) { + xmlSuite.setPackages(PackagesMapper.toXmlPackages((org.testng.xml.jaxb.Packages) o)); + } else if (o instanceof org.testng.xml.jaxb.Test) { + xmlSuite.addTest(TestMapper.toXmlTest((org.testng.xml.jaxb.Test) o)); + } else if (o instanceof org.testng.xml.jaxb.Parameter) { + xmlSuite + .getParameters() + .put( + ((org.testng.xml.jaxb.Parameter) o).getName(), + ((org.testng.xml.jaxb.Parameter) o).getValue()); + } else if (o instanceof org.testng.xml.jaxb.MethodSelectors) { + xmlSuite.setMethodSelectors( + MethodSelectorsMapper.toXmlMethodSelectors((org.testng.xml.jaxb.MethodSelectors) o)); + } else if (o instanceof org.testng.xml.jaxb.SuiteFiles) { + xmlSuite.setSuiteFiles( + SuiteFilesMapper.toXmlSuiteFiles((org.testng.xml.jaxb.SuiteFiles) o)); + } + } + + return xmlSuite; + } +} diff --git a/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/TestMapper.java b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/TestMapper.java new file mode 100644 index 000000000..3ad9dd2e6 --- /dev/null +++ b/testng-jaxb/src/main/java/org/testng/xml/jaxb/mappers/TestMapper.java @@ -0,0 +1,30 @@ +package org.testng.xml.jaxb.mappers; + +import org.testng.xml.XmlTest; +import org.testng.xml.jaxb.Test; + +public class TestMapper { + + public static XmlTest toXmlTest(Test test) { + XmlTest xmlTest = new XmlTest(); + xmlTest.setName(test.getName()); + if (test.getVerbose() != null) { + xmlTest.setVerbose(Integer.parseInt(test.getVerbose())); + } + if (test.getSkipfailedinvocationcounts() != null) { + xmlTest.setSkipFailedInvocationCounts( + Boolean.parseBoolean(test.getSkipfailedinvocationcounts())); + } + if (test.getPreserveOrder() != null) { + xmlTest.setPreserveOrder(Boolean.parseBoolean(test.getPreserveOrder())); + } + if (test.getGroupByInstances() != null) { + xmlTest.setGroupByInstances(Boolean.parseBoolean(test.getGroupByInstances())); + } + if (test.getAllowReturnValues() != null) { + xmlTest.setAllowReturnValues(Boolean.parseBoolean(test.getAllowReturnValues())); + } + xmlTest.setParameters(ParameterMapper.toXmlParameters(test.getParameter())); + return xmlTest; + } +} diff --git a/testng-jaxb/src/main/resources/META-INF/services/org.testng.xml.ISuiteParser b/testng-jaxb/src/main/resources/META-INF/services/org.testng.xml.ISuiteParser new file mode 100644 index 000000000..18e00230c --- /dev/null +++ b/testng-jaxb/src/main/resources/META-INF/services/org.testng.xml.ISuiteParser @@ -0,0 +1 @@ +org.testng.xml.jaxb.JaxbParser diff --git a/testng-jaxb/src/main/resources/testng-1.1.xsd b/testng-jaxb/src/main/resources/testng-1.1.xsd new file mode 100644 index 000000000..02a388e72 --- /dev/null +++ b/testng-jaxb/src/main/resources/testng-1.1.xsd @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testng-jaxb/testng-jaxb-build.gradle.kts b/testng-jaxb/testng-jaxb-build.gradle.kts new file mode 100644 index 000000000..caa7aa20b --- /dev/null +++ b/testng-jaxb/testng-jaxb-build.gradle.kts @@ -0,0 +1,27 @@ +plugins { + id("testng.java-library") + id("com.intershop.gradle.jaxb") version "6.0.0" +} + +dependencies { + api("jakarta.xml.bind:jakarta.xml.bind-api:4.0.2") + api(projects.testngCoreApi) + implementation(projects.testngCore) +} + +jaxb { + javaGen { + register("testng") { + schema = file("src/main/resources/testng-1.1.xsd") + packageName = "org.testng.xml.jaxb" + } + } +} + +sourceSets { + main { + java { + srcDir(tasks.named("jaxbJavaGenTestng")) + } + } +}