Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 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
2 changes: 2 additions & 0 deletions build-logic/code-quality/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ repositories {
dependencies {
implementation("org.sonarqube:org.sonarqube.gradle.plugin:2.8")
implementation("com.github.autostyle:autostyle-plugin-gradle:3.1")
implementation("org.checkerframework:checkerframework-gradle-plugin:0.6.29")
implementation("net.ltgt.gradle:gradle-errorprone-plugin:3.1.0")
}

tasks.withType<KotlinCompile>().configureEach {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import org.checkerframework.gradle.plugin.CheckerFrameworkExtension

plugins {
id("org.checkerframework")
}

dependencies {
checkerFramework("org.checkerframework:checker:3.36.0")
}

plugins.withId("org.checkerframework") {
configure<CheckerFrameworkExtension> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plugins { id("org.checkerframework") } adds checkerframework plugin, so plugins.withId(..) is not needed here.

Something like checkerframework {...} should do.

checkers = listOf(
"org.checkerframework.checker.nullness.NullnessChecker",
"org.checkerframework.checker.optional.OptionalChecker"
)
}
}

tasks.withType<JavaCompile>().configureEach {
// Don't run the checker on generated code.
if (name.startsWith("compileMainGenerated")) {
checkerFramework {
skipCheckerFramework = true
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import net.ltgt.gradle.errorprone.errorprone

plugins {
id("net.ltgt.errorprone")
}

dependencies {
errorprone("com.google.errorprone:error_prone_core:2.20.0")
}

tasks.withType<JavaCompile>().configureEach {
options.errorprone.disableWarningsInGeneratedCode.set(true)
}
2 changes: 2 additions & 0 deletions build-logic/jvm/src/main/kotlin/testng.java.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ plugins {
`java-base`
id("testng.versioning")
id("testng.style")
id("testng.errorprone")
id("testng.checkerframework")
id("testng.repositories")
// Improves Gradle Test logging
// See https://github.com/vlsi/vlsi-release-plugins/tree/master/plugins/gradle-extensions-plugin
Expand Down
129 changes: 77 additions & 52 deletions testng-asserts/src/main/java/org/testng/Assert.java

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions testng-asserts/src/main/java/org/testng/FileAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.File;
import java.io.IOException;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
* Assertion tool for File centric assertions. Conceptually, this is an extension of {@link Assert}.
Expand Down Expand Up @@ -77,7 +78,7 @@ public static void assertFile(File tstvalue) {
* @param expected the expected value
* @param message the assertion error message
*/
public static void assertLength(File tstvalue, long expected, String message) {
public static void assertLength(File tstvalue, long expected, @Nullable String message) {
long actual = -1L;
try {
actual = tstvalue.isDirectory() ? tstvalue.list().length : tstvalue.length();
Expand Down Expand Up @@ -291,7 +292,7 @@ private static void failFile(File path, String actual, String expected, String m
* @param message
*/
private static void failSecurity(
Exception e, File path, String actual, String expected, String message) {
Exception e, File path, String actual, String expected, @Nullable String message) {
String formatted = "";
if (message != null) {
formatted = message + " ";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.Nullable;

/** An assert class with various hooks allowing its behavior to be modified by subclasses. */
public class Assertion implements IAssertLifecycle {
Expand Down Expand Up @@ -41,9 +42,9 @@ public void onBeforeAssert(IAssert<?> assertCommand) {}
public void onAfterAssert(IAssert<?> assertCommand) {}

private abstract static class SimpleAssert<T> implements IAssert<T> {
private final T actual;
private final T expected;
private final String m_message;
private final @Nullable T actual;
private final @Nullable T expected;
private final @Nullable String m_message;

public SimpleAssert(String message) {
this(null, null, message);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.testng.asserts;

import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.testng.collections.Maps;

/**
Expand Down Expand Up @@ -30,7 +31,7 @@ public void assertAll() {
assertAll(null);
}

public void assertAll(String message) {
public void assertAll(@Nullable String message) {
if (!m_errors.isEmpty()) {
StringBuilder sb = new StringBuilder(null == message ? DEFAULT_SOFT_ASSERT_MESSAGE : message);
boolean first = true;
Expand Down
1 change: 1 addition & 0 deletions testng-asserts/testng-asserts-build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ dependencies {
implementation(projects.testngCollections) {
because("Lists.newArrayList")
}
implementation("org.checkerframework:checker-qual:3.36.0")

testImplementation("org.testng:testng:7.3.0") {
because("core depends on assertions and we need testng to test assertions")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.*;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.NonNull;

public final class Lists {

Expand Down Expand Up @@ -51,7 +52,7 @@ public static <K> List<K> newArrayList(int size) {
return new ArrayList<>(size);
}

public static <K> List<K> intersection(List<K> list1, List<K> list2) {
public static <K> List<K> intersection(List<@NonNull K> list1, List<@NonNull K> list2) {
return list1.stream().filter(list2::contains).collect(Collectors.toList());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.testng.collections;

import com.google.errorprone.annotations.InlineMe;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
Expand All @@ -13,6 +14,8 @@ public static <K, V> Map<K, V> newHashMap() {
return new HashMap<>();
}

@Deprecated
@InlineMe(replacement = "new Hashtable<>()", imports = "java.util.Hashtable")
public static <K, V> Map<K, V> newHashtable() {
return new Hashtable<>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.checkerframework.checker.nullness.qual.KeyFor;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

public abstract class MultiMap<K, V, C extends Collection<V>> {
protected final Map<K, C> m_objects;
protected final @NonNull Map<@NonNull K, @NonNull C> m_objects;

protected MultiMap(boolean isSorted) {
if (isSorted) {
Expand All @@ -19,7 +22,7 @@ protected MultiMap(boolean isSorted) {

protected abstract C createValue();

public boolean put(K key, V method) {
public boolean put(@NonNull K key, @NonNull V method) {
AtomicBoolean exists = new AtomicBoolean(true);
return m_objects
.computeIfAbsent(
Expand All @@ -32,58 +35,57 @@ public boolean put(K key, V method) {
&& exists.get();
}

public C get(K key) {
public C get(@NonNull K key) {
return m_objects.computeIfAbsent(key, k -> createValue());
}

public Set<K> keySet() {
public @NonNull Set<K> keySet() {
return new HashSet<>(m_objects.keySet());
}

public boolean containsKey(K k) {
public boolean containsKey(@NonNull K k) {
return m_objects.containsKey(k);
}

@Override
public String toString() {
StringBuilder result = new StringBuilder();
Set<K> indices = keySet();
for (K i : indices) {
result.append("\n ").append(i).append(" <-- ");
for (Object o : m_objects.get(i)) {
result.append(o).append(" ");
for (Map.Entry<K, C> entry : m_objects.entrySet()) {
result.append("\n ").append(entry.getKey()).append(" <-- ");
for (V v : entry.getValue()) {
result.append(v).append(" ");
}
}
return result.toString();
}

public boolean isEmpty() {
return m_objects.size() == 0;
return m_objects.isEmpty();
}

public int size() {
return m_objects.size();
}

public boolean remove(K key, V value) {
public boolean remove(@NonNull K key, @NonNull V value) {
return get(key).remove(value);
}

public C removeAll(K key) {
public @Nullable C removeAll(@NonNull K key) {
return m_objects.remove(key);
}

public Set<Map.Entry<K, C>> entrySet() {
public Set<Map.Entry<@NonNull @KeyFor("this.m_objects") K, @NonNull C>> entrySet() {
return m_objects.entrySet();
}

public Collection<C> values() {
return m_objects.values();
}

public boolean putAll(K k, Collection<? extends V> values) {
public boolean putAll(@NonNull K k, @NonNull Collection<? extends @NonNull V> values) {
boolean result = false;
for (V v : values) {
for (@NonNull V v : values) {
result = put(k, v) || result;
}
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.testng.collections.Maps;

public final class Strings {
Expand All @@ -12,7 +12,10 @@ private Strings() {
}

public static boolean isNullOrEmpty(String string) {
return Optional.ofNullable(string).orElse("").trim().isEmpty();
if (string == null) {
return true;
}
return string.isEmpty();
}

public static boolean isNotNullAndNotEmpty(String string) {
Expand Down Expand Up @@ -52,7 +55,7 @@ public static String escapeHtml(String text) {
return result;
}

public static String valueOf(Map<?, ?> m) {
public static String valueOf(Map<?, @NonNull ?> m) {
return m.values().stream().map(Object::toString).collect(Collectors.joining(" "));
}

Expand Down
5 changes: 5 additions & 0 deletions testng-collections/testng-collections-build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
plugins {
id("testng.java-library")
}

dependencies {
implementation("org.checkerframework:checker-qual:3.36.0")
implementation("com.google.errorprone:error_prone_annotations:2.20.0")
}
5 changes: 3 additions & 2 deletions testng-core-api/src/main/java/org/testng/IAttributes.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
/** A trait that is used by all interfaces that lets the user add or remove their own attributes. */
public interface IAttributes {
/**
* Returns the attribute with the given name.
*
* @param name The name of the attribute to return
* @return The attribute
*/
Object getAttribute(String name);

Expand All @@ -18,7 +19,7 @@ public interface IAttributes {
*/
void setAttribute(String name, Object value);

/** @return all the attributes names. */
/** Returns all the attributes names. */
Set<String> getAttributeNames();

/**
Expand Down
10 changes: 5 additions & 5 deletions testng-core-api/src/main/java/org/testng/IClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
/** <code>IClass</code> represents a test class and a collection of its instances. */
public interface IClass {

/** @return this test class name. This is the name of the corresponding Java class. */
/** Returns this test class name. This is the name of the corresponding Java class. */
String getName();

/** @return the &lt;test&gt; tag this class was found in. */
/** Returns the &lt;test&gt; tag this class was found in. */
XmlTest getXmlTest();

/** @return the *lt;class&gt; tag this class was found in. */
/** Returns the *lt;class&gt; tag this class was found in. */
XmlClass getXmlClass();

/** @return its test name if this class implements org.testng.ITest, null otherwise. */
/** Returns its test name if this class implements org.testng.ITest, null otherwise. */
String getTestName();

/** @return the Java class corresponding to this IClass. */
/** Returns the Java class corresponding to this IClass. */
Class<?> getRealClass();

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.testng;

import org.checkerframework.checker.nullness.qual.NonNull;

/**
* Factory used to create all test instances. This object factory only receives the class in
* parameter.
Expand All @@ -17,7 +19,7 @@ public interface IObjectFactory2 extends ITestObjectFactory {
* @return - The newly created object.
*/
@Deprecated
default Object newInstance(Class<?> cls) {
default Object newInstance(@NonNull Class<?> cls) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return newInstance(cls, new Object[0]);
}
}
Loading