Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.testng.cli;

import org.jspecify.annotations.Nullable;
import org.testng.ITestListener;
import org.testng.ITestNGCliRunner;
import org.testng.TestNG;
Expand Down Expand Up @@ -27,7 +28,7 @@ public abstract class AbstractCliRunner implements ITestNGCliRunner {
protected abstract CliOptions parse(String[] argv);

@Override
public TestNG run(String[] argv, ITestListener listener) {
public TestNG run(String[] argv, @Nullable ITestListener listener) {
TestNG result = new TestNG();

if (null != listener) {
Expand Down
47 changes: 24 additions & 23 deletions testng-cli/src/main/java/org/testng/cli/CliOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.testng.xml.XmlSuite;

/**
Expand Down Expand Up @@ -71,81 +72,81 @@ public class CliOptions {
public List<String> suiteFiles = new ArrayList<>();

/** Level of verbosity. */
public Integer verbose;
public @Nullable Integer verbose;

/** Comma-separated list of group names to be run. */
public String groups;
public @Nullable String groups;

/** Comma-separated list of group names to exclude. */
public String excludedGroups;
public @Nullable String excludedGroups;

/** Output directory. */
public String outputDirectory;
public @Nullable String outputDirectory;

/**
* List of {@code .class} files or list of class names implementing {@code ITestListener} or
* {@code ISuiteListener}.
*/
public String listener;
public @Nullable String listener;

/** An implementation of {@code ListenerComparator} that orders listener execution. */
public String listenerComparator;
public @Nullable String listenerComparator;

/** List of {@code .class} files or list of class names implementing {@code IMethodSelector}. */
public String methodSelectors;
public @Nullable String methodSelectors;

/** Fully qualified class name that implements {@code org.testng.ITestObjectFactory}. */
public String objectFactory;
public @Nullable String objectFactory;

/** Parallel mode (methods, tests or classes). */
public XmlSuite.ParallelMode parallelMode;
public XmlSuite.@Nullable ParallelMode parallelMode;

/** Configuration failure policy (skip or continue). */
public String configFailurePolicy;
public @Nullable String configFailurePolicy;

/** Number of threads to use when running tests in parallel. */
public Integer threadCount;
public @Nullable Integer threadCount;

/** Number of threads to use when running data providers. */
public Integer dataProviderThreadCount;
public @Nullable Integer dataProviderThreadCount;

/** Default name of test suite, if not specified in suite definition file or source code. */
public String suiteName;
public @Nullable String suiteName;

/** Default name of test, if not specified in suite definition file or source code. */
public String testName;
public @Nullable String testName;

/** Extended configuration for custom report listener. */
public String reporter;
public @Nullable String reporter;

/**
* Whether to use the default listeners. This is a {@code String} because the option has an arity
* of one ({@code -usedefaultlisteners false}).
*/
public String useDefaultListeners = "true";

public Boolean skipFailedInvocationCounts;
public @Nullable Boolean skipFailedInvocationCounts;

/** The list of test classes. */
public String testClass;
public @Nullable String testClass;

/** The list of test names to run. */
public String testNames;
public @Nullable String testNames;

/** Ignore missed test names given by {@code -testnames} and continue to run existing tests. */
public boolean ignoreMissedTestNames = false;

/** A jar file containing the tests. */
public String testJar;
public @Nullable String testJar;

/** The full path to the xml file inside the jar file, only valid with {@code -testjar}. */
public String xmlPathInJar = XML_PATH_IN_JAR_DEFAULT;

/** The factory used to create tests. */
public String testRunnerFactory;
public @Nullable String testRunnerFactory;

/** The factory used to create TestNG listeners. */
public String listenerFactory;
public @Nullable String listenerFactory;

/** Comma separated list of test methods. */
public List<String> commandLineMethods = new ArrayList<>();
Expand All @@ -160,10 +161,10 @@ public class CliOptions {
public Boolean alwaysRunListeners = Boolean.TRUE;

/** The threadpool executor factory implementation that TestNG should use. */
public String threadPoolFactoryClass;
public @Nullable String threadPoolFactoryClass;

/** The dependency injector factory implementation that TestNG should use. */
public String dependencyInjectorFactoryClass;
public @Nullable String dependencyInjectorFactoryClass;

/** Should TestNG fail execution if all tests were skipped and nothing was run. */
public Boolean failIfAllTestsSkipped = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.testng.cli;

import org.jspecify.annotations.Nullable;
import org.testng.TestNGException;

/**
Expand All @@ -16,7 +17,12 @@ public CliParseException(String message) {
super(message);
}

public CliParseException(String message, Throwable cause) {
/**
* Only this overload takes a nullable message: it exists to wrap another exception, and {@link
* Throwable#getMessage()} is allowed to return {@code null}. A front end raising a parse failure
* on its own has a message to give and uses {@link #CliParseException(String)}.
*/
public CliParseException(@Nullable String message, Throwable cause) {
super(message, cause);
}
}
5 changes: 5 additions & 0 deletions testng-cli/src/main/java/org/testng/cli/package-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** The parser agnostic command line contract, and the configuration it drives. */
@NullMarked
package org.testng.cli;

import org.jspecify.annotations.NullMarked;
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import org.jspecify.annotations.Nullable;

public final class CollectionUtils {

private CollectionUtils() {}

public static boolean hasElements(Collection<?> c) {
public static boolean hasElements(@Nullable Collection<?> c) {
return c != null && !c.isEmpty();
}

public static boolean hasElements(Map<?, ?> c) {
public static boolean hasElements(@Nullable Map<?, ?> c) {
return c != null && !c.isEmpty();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jspecify.annotations.Nullable;

public abstract class MultiMap<K, V, C extends Collection<V>> {
protected final Map<K, C> m_objects;
Expand Down Expand Up @@ -52,7 +53,7 @@ public String toString() {
Set<K> indices = keySet();
for (K i : indices) {
result.append("\n ").append(i).append(" <-- ");
for (Object o : m_objects.get(i)) {
for (Object o : get(i)) {
result.append(o).append(" ");
}
}
Expand All @@ -71,7 +72,13 @@ public boolean remove(K key, V value) {
return get(key).remove(value);
}

public C removeAll(K key) {
/**
* Drops a key and every value held for it.
*
* @param key the key to drop.
* @return the values that were held, or {@code null} when the key was not present.
*/
public @Nullable C removeAll(K key) {
return m_objects.remove(key);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.testng.util.Strings;

public final class Objects {
Expand All @@ -12,7 +13,7 @@
private final String m_name;
private final String m_value;

public ValueHolder(String name, String value) {

Check warning on line 16 in testng-collections/src/main/java/org/testng/collections/Objects.java

View workflow job for this annotation

GitHub Actions / 26, temurin, ubuntu, Pacific/Chatham, tr_TR

[EffectivelyPrivate] This declaration has public or protected modifiers, but is effectively private.
m_name = name;
m_value = value;
}
Expand All @@ -26,7 +27,7 @@
return m_name + "=" + m_value;
}

public boolean isEmptyString() {

Check warning on line 30 in testng-collections/src/main/java/org/testng/collections/Objects.java

View workflow job for this annotation

GitHub Actions / 26, temurin, ubuntu, Pacific/Chatham, tr_TR

[EffectivelyPrivate] This declaration has public or protected modifiers, but is effectively private.
return Strings.isNullOrEmpty(m_value);
}
}
Expand All @@ -51,17 +52,17 @@
return this;
}

public ToStringHelper add(String name, String value) {
public ToStringHelper add(String name, @Nullable String value) {
values.add(new ValueHolder(name, s(value)));
return this;
}

public ToStringHelper add(String name, Object value) {
public ToStringHelper add(String name, @Nullable Object value) {
values.add(new ValueHolder(name, s(value)));
return this;
}

private String s(Object o) {
private String s(@Nullable Object o) {
return o != null ? (o.toString().isEmpty() ? "\"\"" : o.toString()) : "{null}";
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** Small collection factories and containers shared across TestNG. */
@NullMarked
package org.testng.collections;

import org.jspecify.annotations.NullMarked;
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
Expand All @@ -26,8 +27,11 @@
*/
public class Converter {

// Pre-seeded rather than left null: JCommander reuses a main parameter list it finds in place
// and clears it before the first value, so the empty list changes nothing -- and `required` is
// enforced from the parameter description, not from this field being null.
@Parameter(description = "file1 [file2 file3...]", required = true)
private List<String> m_files;
private List<String> m_files = new ArrayList<>();

@Parameter(names = "-d", description = "The directory where the file(s) will be created")
private String m_outputDirectory = ".";
Expand Down
Loading
Loading