diff --git a/testng-core/src/main/java/org/testng/internal/ClassImpl.java b/testng-core/src/main/java/org/testng/internal/ClassImpl.java index cc682033a7..9bc821ef59 100644 --- a/testng-core/src/main/java/org/testng/internal/ClassImpl.java +++ b/testng-core/src/main/java/org/testng/internal/ClassImpl.java @@ -173,13 +173,12 @@ private static int computeHashCode(IdentifiableObject identifiable) { } private DetailedAttributes newDetailedAttributes(boolean create, String errMsgPrefix) { - DetailedAttributes ea = new DetailedAttributes(); - ea.setXmlTest(m_testContext.getCurrentXmlTest()); - ea.setClasses(m_classes); - ea.setFinder(m_annotationFinder); - ea.setDeclaringClass(m_class); - ea.setErrorMsgPrefix(errMsgPrefix); - ea.setCreate(create); - return ea; + return new DetailedAttributes( + m_class, + m_classes, + m_testContext.getCurrentXmlTest(), + m_annotationFinder, + create, + errMsgPrefix); } } diff --git a/testng-core/src/main/java/org/testng/internal/collections/Pair.java b/testng-core/src/main/java/org/testng/internal/collections/Pair.java index a7072b3f8d..256cc21e7a 100644 --- a/testng-core/src/main/java/org/testng/internal/collections/Pair.java +++ b/testng-core/src/main/java/org/testng/internal/collections/Pair.java @@ -1,5 +1,6 @@ package org.testng.internal.collections; +import org.jspecify.annotations.Nullable; import org.testng.collections.Objects; public class Pair { @@ -28,7 +29,7 @@ public int hashCode() { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (this == obj) { return true; } diff --git a/testng-core/src/main/java/org/testng/internal/collections/ResourceAwareIterator.java b/testng-core/src/main/java/org/testng/internal/collections/ResourceAwareIterator.java index a080ebc18a..ce41dfb4a4 100644 --- a/testng-core/src/main/java/org/testng/internal/collections/ResourceAwareIterator.java +++ b/testng-core/src/main/java/org/testng/internal/collections/ResourceAwareIterator.java @@ -4,6 +4,7 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Iterator; +import org.jspecify.annotations.Nullable; import org.testng.internal.Utils; /** @@ -18,7 +19,7 @@ public class ResourceAwareIterator implements CloseableIterator { private final Iterator delegate; - private final AutoCloseable resource; + private final @Nullable AutoCloseable resource; private boolean closed; /** @@ -26,7 +27,7 @@ public class ResourceAwareIterator implements CloseableIterator { * @param resource the resource to release on {@link #close()}, or {@code null} if there is * nothing to release. */ - public ResourceAwareIterator(Iterator delegate, AutoCloseable resource) { + public ResourceAwareIterator(Iterator delegate, @Nullable AutoCloseable resource) { this.delegate = delegate; this.resource = resource; } @@ -43,7 +44,7 @@ public ResourceAwareIterator(Iterator delegate, AutoCloseable resource) { * iterator was derived from), or {@code null} if there is nothing to release. */ public static CloseableIterator forDataProvider( - Iterator iterator, Type returnType, AutoCloseable resource) { + Iterator iterator, Type returnType, @Nullable AutoCloseable resource) { return new ResourceAwareIterator<>(toObjectArrayIterator(iterator, returnType), resource); } diff --git a/testng-core/src/main/java/org/testng/internal/collections/package-info.java b/testng-core/src/main/java/org/testng/internal/collections/package-info.java new file mode 100644 index 0000000000..9b6a9cd341 --- /dev/null +++ b/testng-core/src/main/java/org/testng/internal/collections/package-info.java @@ -0,0 +1,5 @@ +/** Iterators and small containers used to shape data provider rows and internal state. */ +@NullMarked +package org.testng.internal.collections; + +import org.jspecify.annotations.NullMarked; diff --git a/testng-core/src/main/java/org/testng/internal/invokers/objects/package-info.java b/testng-core/src/main/java/org/testng/internal/invokers/objects/package-info.java new file mode 100644 index 0000000000..64a3b344a1 --- /dev/null +++ b/testng-core/src/main/java/org/testng/internal/invokers/objects/package-info.java @@ -0,0 +1,5 @@ +/** Suite-level state the invokers carry forward, detached from the XML model it came from. */ +@NullMarked +package org.testng.internal.invokers.objects; + +import org.jspecify.annotations.NullMarked; diff --git a/testng-core/src/main/java/org/testng/internal/objects/pojo/BasicAttributes.java b/testng-core/src/main/java/org/testng/internal/objects/pojo/BasicAttributes.java index 7583fb2ae4..bdbdf814ca 100644 --- a/testng-core/src/main/java/org/testng/internal/objects/pojo/BasicAttributes.java +++ b/testng-core/src/main/java/org/testng/internal/objects/pojo/BasicAttributes.java @@ -1,25 +1,26 @@ package org.testng.internal.objects.pojo; +import org.jspecify.annotations.Nullable; import org.testng.IClass; /** Represents the basic attributes associated with object creation. */ public class BasicAttributes { - private final IClass iClass; - private final Class clazz; + private final @Nullable IClass iClass; + private final @Nullable Class clazz; - public BasicAttributes(IClass iClass, Class clazz) { + public BasicAttributes(@Nullable IClass iClass, @Nullable Class clazz) { this.iClass = iClass; this.clazz = clazz; } /** @return - The actual {@link Class} */ - public Class getRawClass() { + public @Nullable Class getRawClass() { return clazz; } /** @return - The wrapped {@link IClass} that represents a TestNG test class. */ - public IClass getTestClass() { + public @Nullable IClass getTestClass() { return iClass; } } diff --git a/testng-core/src/main/java/org/testng/internal/objects/pojo/CreationAttributes.java b/testng-core/src/main/java/org/testng/internal/objects/pojo/CreationAttributes.java index 68e89483da..38e778b98d 100644 --- a/testng-core/src/main/java/org/testng/internal/objects/pojo/CreationAttributes.java +++ b/testng-core/src/main/java/org/testng/internal/objects/pojo/CreationAttributes.java @@ -1,5 +1,6 @@ package org.testng.internal.objects.pojo; +import org.jspecify.annotations.Nullable; import org.testng.ITestContext; import org.testng.internal.invokers.objects.GuiceContext; @@ -7,11 +8,12 @@ public class CreationAttributes { private final BasicAttributes basic; - private final DetailedAttributes detailed; - private final ITestContext context; - private final GuiceContext suiteContext; + private final @Nullable DetailedAttributes detailed; + private final @Nullable ITestContext context; + private final @Nullable GuiceContext suiteContext; - public CreationAttributes(ITestContext ctx, BasicAttributes basic, DetailedAttributes detailed) { + public CreationAttributes( + ITestContext ctx, BasicAttributes basic, @Nullable DetailedAttributes detailed) { this.basic = basic; this.detailed = detailed; this.context = ctx; @@ -25,7 +27,7 @@ public CreationAttributes(BasicAttributes basic, GuiceContext suiteContext) { this.suiteContext = suiteContext; } - public DetailedAttributes getDetailedAttributes() { + public @Nullable DetailedAttributes getDetailedAttributes() { return detailed; } @@ -33,11 +35,11 @@ public BasicAttributes getBasicAttributes() { return basic; } - public ITestContext getContext() { + public @Nullable ITestContext getContext() { return context; } - public GuiceContext getSuiteContext() { + public @Nullable GuiceContext getSuiteContext() { return suiteContext; } } diff --git a/testng-core/src/main/java/org/testng/internal/objects/pojo/DetailedAttributes.java b/testng-core/src/main/java/org/testng/internal/objects/pojo/DetailedAttributes.java index 2e646ec7af..2f99079972 100644 --- a/testng-core/src/main/java/org/testng/internal/objects/pojo/DetailedAttributes.java +++ b/testng-core/src/main/java/org/testng/internal/objects/pojo/DetailedAttributes.java @@ -8,58 +8,49 @@ /** Represents the elaborate set of attributes required for object creation. */ public class DetailedAttributes { - private Class declaringClass; - private Map, IClass> classes; - private XmlTest xmlTest; - private IAnnotationFinder finder; - private boolean create; - private String errorMsgPrefix; + private final Class declaringClass; + private final Map, IClass> classes; + private final XmlTest xmlTest; + private final IAnnotationFinder finder; + private final boolean create; + private final String errorMsgPrefix; + + public DetailedAttributes( + Class declaringClass, + Map, IClass> classes, + XmlTest xmlTest, + IAnnotationFinder finder, + boolean create, + String errorMsgPrefix) { + this.declaringClass = declaringClass; + this.classes = classes; + this.xmlTest = xmlTest; + this.finder = finder; + this.create = create; + this.errorMsgPrefix = errorMsgPrefix; + } public Class getDeclaringClass() { return declaringClass; } - public void setDeclaringClass(Class declaringClass) { - this.declaringClass = declaringClass; - } - public Map, IClass> getClasses() { return classes; } - public void setClasses(Map, IClass> classes) { - this.classes = classes; - } - public XmlTest getXmlTest() { return xmlTest; } - public void setXmlTest(XmlTest xmlTest) { - this.xmlTest = xmlTest; - } - public IAnnotationFinder getFinder() { return finder; } - public void setFinder(IAnnotationFinder finder) { - this.finder = finder; - } - public boolean isCreate() { return create; } - public void setCreate(boolean create) { - this.create = create; - } - public String getErrorMsgPrefix() { return errorMsgPrefix; } - - public void setErrorMsgPrefix(String errorMsgPrefix) { - this.errorMsgPrefix = errorMsgPrefix; - } } diff --git a/testng-core/src/main/java/org/testng/internal/objects/pojo/package-info.java b/testng-core/src/main/java/org/testng/internal/objects/pojo/package-info.java new file mode 100644 index 0000000000..65dc0e0961 --- /dev/null +++ b/testng-core/src/main/java/org/testng/internal/objects/pojo/package-info.java @@ -0,0 +1,5 @@ +/** The attribute bundles the object dispensers are handed to create a test instance. */ +@NullMarked +package org.testng.internal.objects.pojo; + +import org.jspecify.annotations.NullMarked; diff --git a/testng-core/src/main/java/org/testng/internal/thread/graph/GraphOrchestrator.java b/testng-core/src/main/java/org/testng/internal/thread/graph/GraphOrchestrator.java index f1a6bdac27..25a6277a0f 100644 --- a/testng-core/src/main/java/org/testng/internal/thread/graph/GraphOrchestrator.java +++ b/testng-core/src/main/java/org/testng/internal/thread/graph/GraphOrchestrator.java @@ -8,6 +8,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.jspecify.annotations.Nullable; import org.testng.IDynamicGraph; import org.testng.internal.AutoCloseableLock; import org.testng.internal.RuntimeBehavior; @@ -24,7 +25,7 @@ public class GraphOrchestrator { private final IDynamicGraph graph; private final Map> mapping = new ConcurrentHashMap<>(); private final Map upstream = new ConcurrentHashMap<>(); - private final Comparator comparator; + private final @Nullable Comparator comparator; private final IThreadWorkerFactory factory; private final boolean shutdownExecutorOnFinish; private final CountDownLatch completed = new CountDownLatch(1); @@ -35,7 +36,7 @@ public GraphOrchestrator( ExecutorService service, IThreadWorkerFactory factory, IDynamicGraph graph, - Comparator comparator) { + @Nullable Comparator comparator) { this(service, factory, graph, comparator, true); } @@ -49,7 +50,7 @@ public GraphOrchestrator( ExecutorService service, IThreadWorkerFactory factory, IDynamicGraph graph, - Comparator comparator, + @Nullable Comparator comparator, boolean shutdownExecutorOnFinish) { this.service = service; this.graph = graph; diff --git a/testng-core/src/main/java/org/testng/internal/thread/graph/PhoneyWorker.java b/testng-core/src/main/java/org/testng/internal/thread/graph/PhoneyWorker.java index c8d9f3ad51..4631fc03a6 100644 --- a/testng-core/src/main/java/org/testng/internal/thread/graph/PhoneyWorker.java +++ b/testng-core/src/main/java/org/testng/internal/thread/graph/PhoneyWorker.java @@ -1,7 +1,6 @@ package org.testng.internal.thread.graph; import java.util.List; -import javax.annotation.Nonnull; import org.testng.thread.IWorker; class PhoneyWorker implements IWorker { @@ -13,7 +12,8 @@ public PhoneyWorker(long threadId) { @Override public List getTasks() { - return null; + // A PhoneyWorker stands in for a thread id, never for work: it has no tasks to report. + return List.of(); } @Override @@ -27,7 +27,7 @@ public int getPriority() { } @Override - public int compareTo(@Nonnull IWorker o) { + public int compareTo(IWorker o) { return 0; } diff --git a/testng-core/src/main/java/org/testng/internal/thread/graph/package-info.java b/testng-core/src/main/java/org/testng/internal/thread/graph/package-info.java new file mode 100644 index 0000000000..2ef9a42fd7 --- /dev/null +++ b/testng-core/src/main/java/org/testng/internal/thread/graph/package-info.java @@ -0,0 +1,5 @@ +/** Drives a dynamic graph's ready nodes through an executor, worker by worker. */ +@NullMarked +package org.testng.internal.thread.graph; + +import org.jspecify.annotations.NullMarked; diff --git a/testng-core/src/main/java/org/testng/log/package-info.java b/testng-core/src/main/java/org/testng/log/package-info.java new file mode 100644 index 0000000000..4cec819143 --- /dev/null +++ b/testng-core/src/main/java/org/testng/log/package-info.java @@ -0,0 +1,5 @@ +/** The java.util.logging formatter TestNG installs on its own handlers. */ +@NullMarked +package org.testng.log; + +import org.jspecify.annotations.NullMarked; diff --git a/testng-core/src/main/java/org/testng/reporters/util/StackTraceTools.java b/testng-core/src/main/java/org/testng/reporters/util/StackTraceTools.java index f425bef6ac..f400ff8f85 100644 --- a/testng-core/src/main/java/org/testng/reporters/util/StackTraceTools.java +++ b/testng-core/src/main/java/org/testng/reporters/util/StackTraceTools.java @@ -1,5 +1,6 @@ package org.testng.reporters.util; +import org.jspecify.annotations.Nullable; import org.testng.ITestNGMethod; /** @@ -20,7 +21,8 @@ private StackTraceTools() { * @return topmost position of the test method in the stack, or top of stack if method * is not in it. */ - public static int getTestRoot(StackTraceElement[] stack, ITestNGMethod method) { + public static int getTestRoot( + StackTraceElement @Nullable [] stack, @Nullable ITestNGMethod method) { if (stack == null || method == null) { return -1; } @@ -41,7 +43,7 @@ public static int getTestRoot(StackTraceElement[] stack, ITestNGMethod method) { * is not in it. */ public static StackTraceElement[] getTestNGInfrastructure( - StackTraceElement[] stack, ITestNGMethod method) { + StackTraceElement @Nullable [] stack, @Nullable ITestNGMethod method) { if (method == null || stack == null) { return new StackTraceElement[] {}; } diff --git a/testng-core/src/main/java/org/testng/reporters/util/package-info.java b/testng-core/src/main/java/org/testng/reporters/util/package-info.java new file mode 100644 index 0000000000..1a51c09acf --- /dev/null +++ b/testng-core/src/main/java/org/testng/reporters/util/package-info.java @@ -0,0 +1,5 @@ +/** Stack trace slicing for reporters. */ +@NullMarked +package org.testng.reporters.util; + +import org.jspecify.annotations.NullMarked; diff --git a/testng-core/src/main/java/org/testng/thread/package-info.java b/testng-core/src/main/java/org/testng/thread/package-info.java new file mode 100644 index 0000000000..8fb7b357aa --- /dev/null +++ b/testng-core/src/main/java/org/testng/thread/package-info.java @@ -0,0 +1,5 @@ +/** The worker and thread-pool contracts the graph executors are written against. */ +@NullMarked +package org.testng.thread; + +import org.jspecify.annotations.NullMarked; diff --git a/testng-core/src/main/java/org/testng/xml/internal/Parser.java b/testng-core/src/main/java/org/testng/xml/internal/Parser.java index 5548d3841e..d07875a7b6 100644 --- a/testng-core/src/main/java/org/testng/xml/internal/Parser.java +++ b/testng-core/src/main/java/org/testng/xml/internal/Parser.java @@ -13,6 +13,7 @@ import java.util.Map; import java.util.Queue; import java.util.ServiceLoader; +import org.jspecify.annotations.Nullable; import org.testng.xml.IFileParser; import org.testng.xml.IPostProcessor; import org.testng.xml.ISuiteParser; @@ -50,13 +51,13 @@ public class Parser { } /** - * The file name of the xml suite being parsed. This may be null if the Parser has not been - * initialized with a file name. TODO CQ This member is never used. + * The file name of the xml suite being parsed, or {@link #DEFAULT_FILENAME} when the Parser was + * not given one. */ private String m_fileName; - private InputStream m_inputStream; - private IPostProcessor m_postProcessor; + private @Nullable InputStream m_inputStream; + private @Nullable IPostProcessor m_postProcessor; private boolean m_loadClasses = true; @@ -66,7 +67,7 @@ public class Parser { * * @param fileName the filename corresponding to the inputStream or null if unknown. */ - public Parser(String fileName) { + public Parser(@Nullable String fileName) { init(fileName, null); } @@ -79,7 +80,7 @@ public Parser(InputStream is) { init(null, is); } - private void init(String fileName, InputStream is) { + private void init(@Nullable String fileName, @Nullable InputStream is) { m_fileName = fileName != null ? fileName : DEFAULT_FILENAME; m_inputStream = is; } @@ -122,17 +123,15 @@ public Collection parse() throws IOException { List toBeAdded = new ArrayList<>(); List toBeRemoved = new ArrayList<>(); - if (m_fileName != null) { - URI uri = constructURI(m_fileName); - if (uri == null || uri.getScheme() == null) { - uri = new File(m_fileName).toURI(); - } - if ("file".equalsIgnoreCase(uri.getScheme())) { - File mainFile = new File(uri); - toBeParsed.add(mainFile.getCanonicalPath()); - } else { - toBeParsed.add(uri.toString()); - } + URI uri = constructURI(m_fileName); + if (uri == null || uri.getScheme() == null) { + uri = new File(m_fileName).toURI(); + } + if ("file".equalsIgnoreCase(uri.getScheme())) { + File mainFile = new File(uri); + toBeParsed.add(mainFile.getCanonicalPath()); + } else { + toBeParsed.add(uri.toString()); } /* @@ -268,7 +267,7 @@ private static Parser newParser(InputStream is, IPostProcessor processor) { return result; } - private static URI constructURI(String text) { + private static @Nullable URI constructURI(String text) { try { return URI.create(text); } catch (Exception e) { diff --git a/testng-core/src/main/java/org/testng/xml/internal/TestNamesMatcher.java b/testng-core/src/main/java/org/testng/xml/internal/TestNamesMatcher.java index 82eb162b6f..1a37cbafa2 100644 --- a/testng-core/src/main/java/org/testng/xml/internal/TestNamesMatcher.java +++ b/testng-core/src/main/java/org/testng/xml/internal/TestNamesMatcher.java @@ -4,6 +4,7 @@ import java.util.LinkedList; import java.util.List; import java.util.regex.Pattern; +import org.jspecify.annotations.Nullable; import org.testng.TestNGException; import org.testng.log4testng.Logger; import org.testng.util.Strings; @@ -110,13 +111,13 @@ public List getMatchedTests() { return matchedTests; } - private void addIfNotNull(XmlSuite xmlSuite) { + private void addIfNotNull(@Nullable XmlSuite xmlSuite) { if (xmlSuite != null) { cloneSuites.add(xmlSuite); } } - private XmlSuite cloneIfSuiteContainTestsWithNamesMatchingAny(XmlSuite suite) { + private @Nullable XmlSuite cloneIfSuiteContainTestsWithNamesMatchingAny(XmlSuite suite) { List tests = new LinkedList<>(); for (XmlTest xt : suite.getTests()) { if (xt.nameMatchesAny(testNames)) { diff --git a/testng-core/src/main/java/org/testng/xml/internal/package-info.java b/testng-core/src/main/java/org/testng/xml/internal/package-info.java new file mode 100644 index 0000000000..dfd9430d17 --- /dev/null +++ b/testng-core/src/main/java/org/testng/xml/internal/package-info.java @@ -0,0 +1,5 @@ +/** Reads suite files into XmlSuite, and the checks that run over the result. */ +@NullMarked +package org.testng.xml.internal; + +import org.jspecify.annotations.NullMarked;