From 820318be7d862de2f473fb7a190156e8c91188b6 Mon Sep 17 00:00:00 2001 From: Ankur Mhatre Date: Sun, 25 Oct 2026 18:46:52 +0000 Subject: [PATCH] Add junit-6-migration module: JUnit 5.14.4 vs 6.1.3, API diff and behaviour probes Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01YPgGH6aMbSLANL3E2HHmS6 --- README.md | 2 + junit-6-migration/README.md | 32 ++ .../output/01-versions-and-baseline.txt | 11 + junit-6-migration/output/02-removed-api.txt | 318 ++++++++++++++++++ .../output/03-csv-behaviour-5.14.4.txt | 19 ++ .../output/03-csv-behaviour-6.1.3.txt | 18 + .../output/04-vintage-junit4-5.14.4.txt | 2 + .../output/04-vintage-junit4-6.1.3.txt | 2 + .../output/05-old-apis-5.14.4.txt | 40 +++ .../output/05-old-apis-6.1.3.txt | 40 +++ .../output/06-fixed-apis-5.14.4.txt | 32 ++ .../output/06-fixed-apis-6.1.3.txt | 32 ++ junit-6-migration/pom.xml | 84 +++++ junit-6-migration/scripts/api_diff.py | 159 +++++++++ junit-6-migration/scripts/compile-old-apis.sh | 23 ++ junit-6-migration/scripts/run-all.sh | 11 + junit-6-migration/src/compat/FixedApis.java | 15 + junit-6-migration/src/compat/OldApis.java | 17 + .../ankurm/junitmigration/BehaviourTest.java | 86 +++++ .../com/ankurm/junitmigration/CsvProbe.java | 56 +++ .../junitmigration/LegacyJUnit4Test.java | 14 + .../src/test/resources/probe.csv | 5 + 22 files changed, 1018 insertions(+) create mode 100644 junit-6-migration/README.md create mode 100644 junit-6-migration/output/01-versions-and-baseline.txt create mode 100644 junit-6-migration/output/02-removed-api.txt create mode 100644 junit-6-migration/output/03-csv-behaviour-5.14.4.txt create mode 100644 junit-6-migration/output/03-csv-behaviour-6.1.3.txt create mode 100644 junit-6-migration/output/04-vintage-junit4-5.14.4.txt create mode 100644 junit-6-migration/output/04-vintage-junit4-6.1.3.txt create mode 100644 junit-6-migration/output/05-old-apis-5.14.4.txt create mode 100644 junit-6-migration/output/05-old-apis-6.1.3.txt create mode 100644 junit-6-migration/output/06-fixed-apis-5.14.4.txt create mode 100644 junit-6-migration/output/06-fixed-apis-6.1.3.txt create mode 100644 junit-6-migration/pom.xml create mode 100755 junit-6-migration/scripts/api_diff.py create mode 100755 junit-6-migration/scripts/compile-old-apis.sh create mode 100755 junit-6-migration/scripts/run-all.sh create mode 100644 junit-6-migration/src/compat/FixedApis.java create mode 100644 junit-6-migration/src/compat/OldApis.java create mode 100644 junit-6-migration/src/test/java/com/ankurm/junitmigration/BehaviourTest.java create mode 100644 junit-6-migration/src/test/java/com/ankurm/junitmigration/CsvProbe.java create mode 100644 junit-6-migration/src/test/java/com/ankurm/junitmigration/LegacyJUnit4Test.java create mode 100644 junit-6-migration/src/test/resources/probe.csv diff --git a/README.md b/README.md index 9b8beb0..8324344 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,11 @@ Runnable companion code for the testing posts on [ankurm.com](https://ankurm.com | Module | Post | Stack | |---|---|---| | [`mockito/`](mockito) | Mockito 5 Deep Dive: Static, Final and Constructor Mocking, ArgumentCaptor and Strict Stubs | Mockito 5.24.0, JUnit 6.1.3, JDK 25 | +| [`junit-6-migration/`](junit-6-migration) | JUnit 5 to 6 Migration: What Was Removed, What Changed and How to Upgrade | JUnit 5.14.4 and 6.1.3, JDK 25 | Every module keeps the real output of its tests in `output/`. Each test writes the transcript and asserts the same facts, so the numbers in the posts fail the build if they stop being true. ```bash cd mockito && ./scripts/run-all.sh +cd ../junit-6-migration && ./scripts/run-all.sh ``` diff --git a/junit-6-migration/README.md b/junit-6-migration/README.md new file mode 100644 index 0000000..a3304fc --- /dev/null +++ b/junit-6-migration/README.md @@ -0,0 +1,32 @@ +# junit-6-migration + +Companion module for the ankurm.com article on **migrating from JUnit 5 to JUnit 6**. The same tests run on JUnit 5.14.4 and 6.1.3, and the two +releases are compared jar against jar. Nothing here is copied from release notes: each file in `output/` was produced by running something. + +## Versions + +| Component | Version | Notes | +|---|---|---| +| JUnit (before) | `5.14.4` Jupiter / `1.14.4` Platform | last 5.x release on Maven Central at the time of writing | +| JUnit (after) | `6.1.3` | Jupiter, Platform and Vintage all share this one number | +| JUnit 4 | `4.13.2` | only for the Vintage check | +| Java | build on `25`, `--release 17` | JUnit 6 jars need Java 17 | + +## Run + +```bash +./scripts/run-all.sh +``` + +## Output + +| File | What it shows | +|---|---| +| `01-versions-and-baseline.txt` | version numbers and the Java level of each jar's class files | +| `02-removed-api.txt` | public classes and members in 5.14.4 that are not in 6.1.3, and whether 5.14.4 had deprecated them | +| `03-csv-behaviour-.txt` | one set of `@CsvSource` and `@CsvFileSource` cases run on each version | +| `04-vintage-junit4-.txt` | a JUnit 4 test run through the Vintage engine on each version | +| `05-old-apis-.txt` | what the compiler says about three deprecated 5.x APIs on each version | +| `06-fixed-apis-.txt` | the replacements compile on both versions | + +`pom.xml` has two profiles, `junit5` and `junit6`, that change nothing but `junit.version`. diff --git a/junit-6-migration/output/01-versions-and-baseline.txt b/junit-6-migration/output/01-versions-and-baseline.txt new file mode 100644 index 0000000..8e46353 --- /dev/null +++ b/junit-6-migration/output/01-versions-and-baseline.txt @@ -0,0 +1,11 @@ +artifact 5.x jar 6.x jar +junit-jupiter-api 5.14.4 (Java 8) 6.1.3 (Java 17) +junit-jupiter-engine 5.14.4 (Java 8) 6.1.3 (Java 17) +junit-jupiter-params 5.14.4 (Java 8) 6.1.3 (Java 17) +junit-platform-commons 1.14.4 (Java 8) 6.1.3 (Java 17) +junit-platform-engine 1.14.4 (Java 8) 6.1.3 (Java 17) +junit-platform-launcher 1.14.4 (Java 8) 6.1.3 (Java 17) +junit-platform-suite-api 1.14.4 (Java 8) 6.1.3 (Java 17) +junit-platform-suite-engine 1.14.4 (Java 8) 6.1.3 (Java 17) +junit-platform-testkit 1.14.4 (Java 8) 6.1.3 (Java 17) +junit-vintage-engine 5.14.4 (Java 8) 6.1.3 (Java 17) diff --git a/junit-6-migration/output/02-removed-api.txt b/junit-6-migration/output/02-removed-api.txt new file mode 100644 index 0000000..f25e6ad --- /dev/null +++ b/junit-6-migration/output/02-removed-api.txt @@ -0,0 +1,318 @@ +== junit-jupiter-api: public classes removed: 6, members removed from classes that remain: 8, new classes: 64 + class org.junit.jupiter.api.Assertions$TimeoutFailureFactory [NOT deprecated in 5.x] + class org.junit.jupiter.api.AssertionsKt$assertDoesNotThrow$3 [NOT deprecated in 5.x] + class org.junit.jupiter.api.AssertionsKt$assertThrows$4 [NOT deprecated in 5.x] + class org.junit.jupiter.api.AssertionsKt$evaluateAndWrap$1 [NOT deprecated in 5.x] + class org.junit.jupiter.api.AssertionsKt$evaluateAndWrap$2 [NOT deprecated in 5.x] + class org.junit.jupiter.api.MethodOrderer$Alphanumeric [deprecated in 5.x] + member org.junit.jupiter.api.Assertions: public static T assertTimeoutPreemptively(java.time.Duration, org.junit.jupiter.api.function.ThrowingSupplier, java.util.function.Supplier, org.junit.jupiter.api.Assertions$TimeoutFailureFactory) throws E [NOT deprecated in 5.x] + member org.junit.jupiter.api.AssertionsKt: public static final org.junit.jupiter.api.function.ThrowingSupplier evaluateAndWrap(kotlin.jvm.functions.Function0) [NOT deprecated in 5.x] + member org.junit.jupiter.api.extension.ExtensionContext: public abstract java.util.Optional getConfigurationParameter(java.lang.String, java.util.function.Function) [NOT deprecated in 5.x] + member org.junit.jupiter.api.extension.ExtensionContext$Store: public abstract java.lang.Object getOrComputeIfAbsent(K, java.util.function.Function) [NOT deprecated in 5.x] + member org.junit.jupiter.api.extension.ExtensionContext$Store: public abstract V getOrComputeIfAbsent(K, java.util.function.Function, java.lang.Class) [NOT deprecated in 5.x] + member org.junit.jupiter.api.extension.InvocationInterceptor: public default void interceptDynamicTest(org.junit.jupiter.api.extension.InvocationInterceptor$Invocation, org.junit.jupiter.api.extension.ExtensionContext) throws java.lang.Throwable [deprecated in 5.x] + member org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider: public abstract java.util.stream.Stream provideTestTemplateInvocationContexts(org.junit.jupiter.api.extension.ExtensionContext) [NOT deprecated in 5.x] + member org.junit.jupiter.api.io.TempDir: public static final java.lang.String SCOPE_PROPERTY_NAME [deprecated in 5.x] +== junit-jupiter-engine: public classes removed: 0, members removed from classes that remain: 30, new classes: 17 + member org.junit.jupiter.engine.Constants: public static final java.lang.String TEMP_DIR_SCOPE_PROPERTY_NAME [deprecated in 5.x] + member org.junit.jupiter.engine.config.CachingJupiterConfiguration: public java.util.Optional getRawConfigurationParameter(java.lang.String, java.util.function.Function) [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.DefaultJupiterConfiguration: public org.junit.jupiter.engine.config.DefaultJupiterConfiguration(org.junit.platform.engine.ConfigurationParameters, org.junit.platform.engine.OutputDirectoryCreator) [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.DefaultJupiterConfiguration: public java.util.Optional getRawConfigurationParameter(java.lang.String, java.util.function.Function) [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.EnumConfigurationParameterConverter: public E get(java.lang.String, java.util.function.Function>, E) [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String EXTENSIONS_AUTODETECTION_INCLUDE_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String EXTENSIONS_AUTODETECTION_EXCLUDE_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String DEACTIVATE_CONDITIONS_PATTERN_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String DEFAULT_EXECUTION_MODE_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String EXTENSIONS_TIMEOUT_THREAD_DUMP_ENABLED_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public static final java.lang.String DEFAULT_TEST_INSTANTIATION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.engine.config.JupiterConfiguration: public abstract java.util.Optional getRawConfigurationParameter(java.lang.String, java.util.function.Function) [NOT deprecated in 5.x] + member org.junit.jupiter.engine.descriptor.ClassTestDescriptor: public org.junit.platform.engine.support.hierarchical.Node$ExecutionMode getExecutionMode() [NOT deprecated in 5.x] + member org.junit.jupiter.engine.descriptor.JupiterTestDescriptor: public org.junit.platform.engine.support.hierarchical.Node$ExecutionMode getExecutionMode() [NOT deprecated in 5.x] + member org.junit.jupiter.engine.discovery.AbstractOrderingVisitor$DescriptorWrapperOrderer: protected static org.junit.jupiter.engine.discovery.AbstractOrderingVisitor$DescriptorWrapperOrderer noop() [NOT deprecated in 5.x] + member org.junit.jupiter.engine.discovery.AbstractOrderingVisitor$MessageGenerator: public abstract java.lang.String generateMessage(int) [NOT deprecated in 5.x] + member org.junit.jupiter.engine.discovery.DiscoverySelectorResolver: public org.junit.jupiter.engine.discovery.DiscoverySelectorResolver() [NOT deprecated in 5.x] + member org.junit.jupiter.engine.discovery.DiscoverySelectorResolver: public void resolveSelectors(org.junit.platform.engine.EngineDiscoveryRequest, org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor) [NOT deprecated in 5.x] + member org.junit.jupiter.engine.execution.NamespaceAwareStore: public java.lang.Object getOrComputeIfAbsent(K, java.util.function.Function) [NOT deprecated in 5.x] + member org.junit.jupiter.engine.execution.NamespaceAwareStore: public V getOrComputeIfAbsent(K, java.util.function.Function, java.lang.Class) [NOT deprecated in 5.x] + member org.junit.jupiter.engine.execution.ParameterResolutionUtils: public org.junit.jupiter.engine.execution.ParameterResolutionUtils() [NOT deprecated in 5.x] + member org.junit.jupiter.engine.support.JupiterThrowableCollectorFactory: public org.junit.jupiter.engine.support.JupiterThrowableCollectorFactory() [NOT deprecated in 5.x] +== junit-jupiter-params: public classes removed: 198, members removed from classes that remain: 5, new classes: 81 + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.BooleanString [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Convert [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Copy [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.EnumOptions [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.FixedWidth [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Format [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.HeaderTransformer [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Headers [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.LowerCase [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Nested [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.NullString [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Parsed [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Replace [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Trim [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.UpperCase [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Validate [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.helpers.AnnotationHelper [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.helpers.AnnotationRegistry [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.helpers.FieldMapping [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.helpers.MethodDescriptor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.helpers.MethodFilter [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.helpers.TransformedHeader [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.AbstractParser [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.AbstractWriter [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.ArgumentUtils [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.ColumnMap [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.CommonParserSettings [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.CommonSettings [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.CommonWriterSettings [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.Context [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.ContextSnapshot [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.ContextWrapper [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.ConversionProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.DataProcessingException [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.DataValidationException [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.DefaultContext [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.DefaultConversionProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.DefaultParsingContext [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.Format [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.IterableResult [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.NoopProcessorErrorHandler [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.NormalizedString [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.ParserOutput [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.ParsingContext [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.ParsingContextSnapshot [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.ParsingContextWrapper [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.ProcessorErrorHandler [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.ResultIterator [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.RetryableErrorHandler [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.RowProcessorErrorHandler [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.StringCache [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.TextParsingException [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.TextWritingException [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.beans.BeanHelper [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.beans.PropertyWrapper [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.AllIndexesSelector [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.ColumnMapper [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.ColumnMapping [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.ExcludeFieldEnumSelector [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.ExcludeFieldIndexSelector [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.ExcludeFieldNameSelector [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.FieldConversionMapping [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.FieldEnumSelector [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.FieldIndexSelector [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.FieldNameSelector [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.FieldSelector [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields.FieldSet [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.AbstractCharInputReader [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.BomInput [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.BomInput$BytesProcessedNotification [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.CharAppender [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.CharInput [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.CharInputReader [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.DefaultCharAppender [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.DefaultCharInputReader [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.EOFException [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.ElasticCharAppender [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.ExpandingCharAppender [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.InputAnalysisProcess [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.LineSeparatorDetector [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.LookaheadCharInputReader [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.NoopCharAppender [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.WriterCharAppender [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.concurrent.ConcurrentCharInputReader [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.iterators.RecordIterator [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.iterators.RowIterator [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.AbstractRowProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.BatchedColumnProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.BatchedObjectColumnProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.BeanListProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.BeanProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.BeanWriterProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.ColumnProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.CompositeRowProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.ConcurrentRowProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.CustomMatcher [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.InputValueSwitch [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.MasterDetailListProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.MasterDetailProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.MasterDetailRecord [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.MultiBeanListProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.MultiBeanProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.MultiBeanRowProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.NoopRowProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.ObjectColumnProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.ObjectRowListProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.ObjectRowProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.ObjectRowWriterProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.OutputValueSwitch [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.RowListProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.RowPlacement [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.RowProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.RowProcessorSwitch [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.RowWriterProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.RowWriterProcessorSwitch [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractBatchedColumnProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractBatchedObjectColumnProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractBeanListProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractBeanProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractColumnProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractConcurrentProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractInputValueSwitch [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractListProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractMasterDetailListProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractMasterDetailProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractMultiBeanListProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractMultiBeanProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractMultiBeanRowProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractObjectColumnProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractObjectListProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractObjectProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.AbstractProcessorSwitch [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.BeanConversionProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.ColumnOrderDependent [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.CompositeProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.NoopProcessor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core.Processor [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.record.AbstractRecordFactory [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.record.Record [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.record.RecordFactory [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.record.RecordMetaData [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.routine.AbstractRoutines [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.common.routine.InputDimension [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.BigDecimalConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.BigIntegerConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.BooleanConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.ByteConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.CalendarConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.CharacterConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.Conversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.Conversions [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.DateConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.DoubleConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.EnumConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.EnumSelector [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.FloatConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.FormattedBigDecimalConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.FormattedConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.FormattedDateConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.IntegerConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.LongConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.LowerCaseConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.NullConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.NullStringConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.NumericConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.ObjectConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.RegexConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.ShortConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.ToStringConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.TrimConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.UpperCaseConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.ValidatedConversion [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.conversions.Validator [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.csv.Csv [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.csv.CsvFormat [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.csv.CsvFormatDetector [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.csv.CsvParser [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.csv.CsvParserSettings [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.csv.CsvRoutines [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.csv.CsvWriter [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.csv.CsvWriterSettings [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.csv.UnescapedQuoteHandling [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.fixed.FieldAlignment [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.fixed.FixedWidthFieldLengths [deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.fixed.FixedWidthFields [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.fixed.FixedWidthFormat [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.fixed.FixedWidthParser [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.fixed.FixedWidthParserSettings [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.fixed.FixedWidthRoutines [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.fixed.FixedWidthWriter [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.fixed.FixedWidthWriterSettings [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.tsv.TsvFormat [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.tsv.TsvParser [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.tsv.TsvParserSettings [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.tsv.TsvRoutines [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.tsv.TsvWriter [NOT deprecated in 5.x] + class org.junit.jupiter.params.shadow.com.univocity.parsers.tsv.TsvWriterSettings [NOT deprecated in 5.x] + member org.junit.jupiter.params.ResolutionCache$Concurrent: public java.lang.Object resolve(org.junit.jupiter.params.support.ParameterDeclaration, java.util.function.Supplier) [NOT deprecated in 5.x] + member org.junit.jupiter.params.aggregator.DefaultArgumentsAccessor: public static org.junit.jupiter.params.aggregator.DefaultArgumentsAccessor create(org.junit.jupiter.api.extension.ExtensionContext, int, java.lang.ClassLoader, java.lang.Object[]) [NOT deprecated in 5.x] + member org.junit.jupiter.params.converter.DefaultArgumentConverter: public static final java.lang.String DEFAULT_LOCALE_CONVERSION_FORMAT_PROPERTY_NAME [NOT deprecated in 5.x] + member org.junit.jupiter.params.converter.DefaultArgumentConverter: public org.junit.jupiter.params.converter.DefaultArgumentConverter(org.junit.jupiter.api.extension.ExtensionContext) [NOT deprecated in 5.x] + member org.junit.jupiter.params.provider.CsvFileSource: public abstract java.lang.String lineSeparator() [NOT deprecated in 5.x] +== junit-platform-commons: public classes removed: 2, members removed from classes that remain: 13, new classes: 16 + class org.junit.platform.commons.util.BlacklistedExceptions [deprecated in 5.x] + class org.junit.platform.commons.util.PreconditionViolationException [deprecated in 5.x] + member org.junit.platform.commons.support.ReflectionSupport: public static java.util.Optional> loadClass(java.lang.String) [deprecated in 5.x] + member org.junit.platform.commons.util.CollectionUtils: public static java.util.Set toSet(T[]) [NOT deprecated in 5.x] + member org.junit.platform.commons.util.CollectionUtils: public static java.util.stream.Collector> toUnmodifiableList() [NOT deprecated in 5.x] + member org.junit.platform.commons.util.KotlinReflectionUtils: public org.junit.platform.commons.util.KotlinReflectionUtils() [NOT deprecated in 5.x] + member org.junit.platform.commons.util.ModuleUtils: public org.junit.platform.commons.util.ModuleUtils() [NOT deprecated in 5.x] + member org.junit.platform.commons.util.ModuleUtils: public static boolean isJavaPlatformModuleSystemAvailable() [NOT deprecated in 5.x] + member org.junit.platform.commons.util.ReflectionUtils: public static java.util.Optional readFieldValue(java.lang.Class, java.lang.String, T) [deprecated in 5.x] + member org.junit.platform.commons.util.ReflectionUtils: public static java.util.Optional readFieldValue(java.lang.reflect.Field) [deprecated in 5.x] + member org.junit.platform.commons.util.ReflectionUtils: public static java.util.Optional readFieldValue(java.lang.reflect.Field, java.lang.Object) [deprecated in 5.x] + member org.junit.platform.commons.util.ReflectionUtils: public static java.util.List readFieldValues(java.util.List, java.lang.Object) [NOT deprecated in 5.x] + member org.junit.platform.commons.util.ReflectionUtils: public static java.util.List readFieldValues(java.util.List, java.lang.Object, java.util.function.Predicate) [NOT deprecated in 5.x] + member org.junit.platform.commons.util.ReflectionUtils: public static java.util.Optional> loadClass(java.lang.String) [deprecated in 5.x] + member org.junit.platform.commons.util.ReflectionUtils: public static java.util.Optional> loadClass(java.lang.String, java.lang.ClassLoader) [deprecated in 5.x] +== junit-platform-engine: public classes removed: 3, members removed from classes that remain: 29, new classes: 36 + class org.junit.platform.engine.support.filter.ClasspathScanningSupport [deprecated in 5.x] + class org.junit.platform.engine.support.hierarchical.SingleTestExecutor [deprecated in 5.x] + class org.junit.platform.engine.support.hierarchical.SingleTestExecutor$Executable [NOT deprecated in 5.x] + member org.junit.platform.engine.ConfigurationParameters: public default java.util.Optional get(java.lang.String, java.util.function.Function) [NOT deprecated in 5.x] + member org.junit.platform.engine.ConfigurationParameters: public abstract int size() [deprecated in 5.x] + member org.junit.platform.engine.ExecutionRequest: public static org.junit.platform.engine.ExecutionRequest create(org.junit.platform.engine.TestDescriptor, org.junit.platform.engine.EngineExecutionListener, org.junit.platform.engine.ConfigurationParameters, org.junit.platform.engine.OutputDirectoryCreator, org.junit.platform.engine.support.store.NamespacedHierarchicalStore) [NOT deprecated in 5.x] + member org.junit.platform.engine.UniqueId: public final java.util.Optional getEngineId() [NOT deprecated in 5.x] + member org.junit.platform.engine.UniqueId: public final java.util.List getSegments() [NOT deprecated in 5.x] + member org.junit.platform.engine.UniqueId: public final org.junit.platform.engine.UniqueId append(java.lang.String, java.lang.String) [NOT deprecated in 5.x] + member org.junit.platform.engine.UniqueId: public final org.junit.platform.engine.UniqueId append(org.junit.platform.engine.UniqueId$Segment) [NOT deprecated in 5.x] + member org.junit.platform.engine.discovery.MethodSelector: public java.lang.String getMethodParameterTypes() [deprecated in 5.x] + member org.junit.platform.engine.discovery.NestedMethodSelector: public java.lang.String getMethodParameterTypes() [deprecated in 5.x] + member org.junit.platform.engine.reporting.ReportEntry: public org.junit.platform.engine.reporting.ReportEntry() [deprecated in 5.x] + member org.junit.platform.engine.support.config.PrefixedConfigurationParameters: public java.util.Optional get(java.lang.String, java.util.function.Function) [NOT deprecated in 5.x] + member org.junit.platform.engine.support.config.PrefixedConfigurationParameters: public int size() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.ClassSource: public final java.lang.String getClassName() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.ClassSource: public final java.lang.Class getJavaClass() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.ClassSource: public final java.util.Optional getPosition() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.ClasspathResourceSource: public final java.util.Optional getPosition() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.CompositeTestSource: public final java.util.List getSources() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.DirectorySource: public final java.net.URI getUri() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.DirectorySource: public final java.io.File getFile() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.FileSource: public final java.net.URI getUri() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.FileSource: public final java.io.File getFile() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.FileSource: public final java.util.Optional getPosition() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.MethodSource: public final java.lang.String getMethodName() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.MethodSource: public final java.lang.String getMethodParameterTypes() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.MethodSource: public final java.lang.Class getJavaClass() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.MethodSource: public final java.lang.reflect.Method getJavaMethod() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.descriptor.PackageSource: public final java.lang.String getPackageName() [NOT deprecated in 5.x] + member org.junit.platform.engine.support.store.NamespacedHierarchicalStore: public java.lang.Object getOrComputeIfAbsent(N, K, java.util.function.Function) [NOT deprecated in 5.x] + member org.junit.platform.engine.support.store.NamespacedHierarchicalStore: public V getOrComputeIfAbsent(N, K, java.util.function.Function, java.lang.Class) throws org.junit.platform.engine.support.store.NamespacedHierarchicalStoreException [NOT deprecated in 5.x] +== junit-platform-launcher: public classes removed: 1, members removed from classes that remain: 5, new classes: 28 + class org.junit.platform.launcher.listeners.LegacyReportingUtils [deprecated in 5.x] + member org.junit.platform.launcher.TestPlan: public void add(org.junit.platform.launcher.TestIdentifier) [deprecated in 5.x] + member org.junit.platform.launcher.TestPlan: public java.util.Set getChildren(java.lang.String) [deprecated in 5.x] + member org.junit.platform.launcher.core.EngineExecutionOrchestrator: public void execute(org.junit.platform.launcher.core.LauncherDiscoveryResult, org.junit.platform.engine.EngineExecutionListener, org.junit.platform.launcher.TestExecutionListener, org.junit.platform.engine.support.store.NamespacedHierarchicalStore) [NOT deprecated in 5.x] + member org.junit.platform.launcher.core.EngineExecutionOrchestrator: public void execute(org.junit.platform.launcher.core.LauncherDiscoveryResult, org.junit.platform.engine.EngineExecutionListener, org.junit.platform.engine.support.store.NamespacedHierarchicalStore) [NOT deprecated in 5.x] + member org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder: public org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder() [deprecated in 5.x] +== junit-platform-suite-api: public classes removed: 1, members removed from classes that remain: 0, new classes: 1 + class org.junit.platform.suite.api.UseTechnicalNames [deprecated in 5.x] +== junit-platform-suite-engine: public classes removed: 0, members removed from classes that remain: 0, new classes: 4 +== junit-platform-testkit: public classes removed: 0, members removed from classes that remain: 3, new classes: 2 + member org.junit.platform.testkit.engine.EngineTestKit: public static org.junit.platform.testkit.engine.EngineExecutionResults execute(java.lang.String, org.junit.platform.engine.EngineDiscoveryRequest) [deprecated in 5.x] + member org.junit.platform.testkit.engine.EngineTestKit: public static org.junit.platform.testkit.engine.EngineExecutionResults execute(org.junit.platform.engine.TestEngine, org.junit.platform.engine.EngineDiscoveryRequest) [deprecated in 5.x] + member org.junit.platform.testkit.engine.EngineTestKit$Builder: public org.junit.platform.testkit.engine.EngineTestKit$Builder filters(org.junit.platform.engine.DiscoveryFilter...) [deprecated in 5.x] +== junit-vintage-engine: public classes removed: 0, members removed from classes that remain: 4, new classes: 6 + member org.junit.vintage.engine.descriptor.VintageEngineDescriptor: public java.util.Set getModifiableChildren() [NOT deprecated in 5.x] + member org.junit.vintage.engine.execution.RunnerExecutor: public org.junit.vintage.engine.execution.RunnerExecutor(org.junit.platform.engine.EngineExecutionListener) [NOT deprecated in 5.x] + member org.junit.vintage.engine.execution.VintageExecutor: public org.junit.vintage.engine.execution.VintageExecutor(org.junit.vintage.engine.descriptor.VintageEngineDescriptor, org.junit.platform.engine.EngineExecutionListener, org.junit.platform.engine.ExecutionRequest) [NOT deprecated in 5.x] + member org.junit.vintage.engine.execution.VintageExecutor: public void executeAllChildren() [NOT deprecated in 5.x] diff --git a/junit-6-migration/output/03-csv-behaviour-5.14.4.txt b/junit-6-migration/output/03-csv-behaviour-5.14.4.txt new file mode 100644 index 0000000..ae6b94e --- /dev/null +++ b/junit-6-migration/output/03-csv-behaviour-5.14.4.txt @@ -0,0 +1,19 @@ +JUnit 5.14.4 +FAILED [method] columnLongerThanLimit(String, int) -> CsvParsingException: Failed to parse CSV input configured via @org.junit.jupiter.params.provider.CsvSource(emptyValue="", delimiter... +SUCCESSFUL [1] x, 1 +SUCCESSFUL [2] y, 2 +SUCCESSFUL [1] apple, 1 +SUCCESSFUL [2] a,b, 2 +SUCCESSFUL [3] padded, 3 +SUCCESSFUL [4] , 4 +SUCCESSFUL [5] null, 5 +SUCCESSFUL [6] NIL, 6 +SUCCESSFUL [7] it's, 7 +SUCCESSFUL [8] "dq", 8 +SUCCESSFUL [1] name = widget, qty = 4 +SUCCESSFUL [2] name = multi word, qty = 5 +SUCCESSFUL [1] one, 1 +SUCCESSFUL [2] two, with comma, 2 +SUCCESSFUL [3] line +break, 3 +SUCCESSFUL [1] a diff --git a/junit-6-migration/output/03-csv-behaviour-6.1.3.txt b/junit-6-migration/output/03-csv-behaviour-6.1.3.txt new file mode 100644 index 0000000..34c4a4e --- /dev/null +++ b/junit-6-migration/output/03-csv-behaviour-6.1.3.txt @@ -0,0 +1,18 @@ +JUnit 6.1.3 +FAILED [method] columnLongerThanLimit(String, int) -> CsvParsingException: Failed to parse CSV input configured via @org.junit.jupiter.params.provider.CsvSource(emptyValue="", delimiter... +SUCCESSFUL [1] "x", "1" +SUCCESSFUL [2] "y", "2" +SUCCESSFUL [1] "apple", "1" +SUCCESSFUL [2] "a,b", "2" +SUCCESSFUL [3] "padded", "3" +SUCCESSFUL [4] "", "4" +SUCCESSFUL [5] null, "5" +SUCCESSFUL [6] "NIL", "6" +SUCCESSFUL [7] "it's", "7" +SUCCESSFUL [8] "\"dq\"", "8" +SUCCESSFUL [1] name = "widget", qty = "4" +SUCCESSFUL [2] name = "multi word", qty = "5" +SUCCESSFUL [1] "one", "1" +SUCCESSFUL [2] "two, with comma", "2" +SUCCESSFUL [3] "line\nbreak", "3" +SUCCESSFUL [1] "a" diff --git a/junit-6-migration/output/04-vintage-junit4-5.14.4.txt b/junit-6-migration/output/04-vintage-junit4-5.14.4.txt new file mode 100644 index 0000000..104665c --- /dev/null +++ b/junit-6-migration/output/04-vintage-junit4-5.14.4.txt @@ -0,0 +1,2 @@ +JUnit 5.14.4 +SUCCESSFUL stillRuns diff --git a/junit-6-migration/output/04-vintage-junit4-6.1.3.txt b/junit-6-migration/output/04-vintage-junit4-6.1.3.txt new file mode 100644 index 0000000..d0866c4 --- /dev/null +++ b/junit-6-migration/output/04-vintage-junit4-6.1.3.txt @@ -0,0 +1,2 @@ +JUnit 6.1.3 +SUCCESSFUL stillRuns diff --git a/junit-6-migration/output/05-old-apis-5.14.4.txt b/junit-6-migration/output/05-old-apis-5.14.4.txt new file mode 100644 index 0000000..cceb3a1 --- /dev/null +++ b/junit-6-migration/output/05-old-apis-5.14.4.txt @@ -0,0 +1,40 @@ +JUnit 5.14.4, compiling OldApis.java +src/compat/OldApis.java:1: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.MethodOrderer; + ^ +src/compat/OldApis.java:2: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.Test; + ^ +src/compat/OldApis.java:3: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.TestMethodOrder; + ^ +src/compat/OldApis.java:4: error: package org.junit.jupiter.api.io does not exist +import org.junit.jupiter.api.io.TempDir; + ^ +src/compat/OldApis.java:5: error: package org.junit.platform.commons.support does not exist +import org.junit.platform.commons.support.ReflectionSupport; + ^ +src/compat/OldApis.java:8: error: cannot find symbol +@TestMethodOrder(MethodOrderer.Alphanumeric.class) + ^ + symbol: class TestMethodOrder +src/compat/OldApis.java:8: error: package MethodOrderer does not exist +@TestMethodOrder(MethodOrderer.Alphanumeric.class) + ^ +src/compat/OldApis.java:11: error: cannot find symbol + @Test + ^ + symbol: class Test + location: class OldApis +src/compat/OldApis.java:13: error: cannot find symbol + Object loaded = ReflectionSupport.loadClass("java.lang.String"); + ^ + symbol: variable ReflectionSupport + location: class OldApis +src/compat/OldApis.java:14: error: cannot find symbol + String property = TempDir.SCOPE_PROPERTY_NAME; + ^ + symbol: variable TempDir + location: class OldApis +10 errors +javac exit status: 1 diff --git a/junit-6-migration/output/05-old-apis-6.1.3.txt b/junit-6-migration/output/05-old-apis-6.1.3.txt new file mode 100644 index 0000000..a34078b --- /dev/null +++ b/junit-6-migration/output/05-old-apis-6.1.3.txt @@ -0,0 +1,40 @@ +JUnit 6.1.3, compiling OldApis.java +src/compat/OldApis.java:1: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.MethodOrderer; + ^ +src/compat/OldApis.java:2: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.Test; + ^ +src/compat/OldApis.java:3: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.TestMethodOrder; + ^ +src/compat/OldApis.java:4: error: package org.junit.jupiter.api.io does not exist +import org.junit.jupiter.api.io.TempDir; + ^ +src/compat/OldApis.java:5: error: package org.junit.platform.commons.support does not exist +import org.junit.platform.commons.support.ReflectionSupport; + ^ +src/compat/OldApis.java:8: error: cannot find symbol +@TestMethodOrder(MethodOrderer.Alphanumeric.class) + ^ + symbol: class TestMethodOrder +src/compat/OldApis.java:8: error: package MethodOrderer does not exist +@TestMethodOrder(MethodOrderer.Alphanumeric.class) + ^ +src/compat/OldApis.java:11: error: cannot find symbol + @Test + ^ + symbol: class Test + location: class OldApis +src/compat/OldApis.java:13: error: cannot find symbol + Object loaded = ReflectionSupport.loadClass("java.lang.String"); + ^ + symbol: variable ReflectionSupport + location: class OldApis +src/compat/OldApis.java:14: error: cannot find symbol + String property = TempDir.SCOPE_PROPERTY_NAME; + ^ + symbol: variable TempDir + location: class OldApis +10 errors +javac exit status: 1 diff --git a/junit-6-migration/output/06-fixed-apis-5.14.4.txt b/junit-6-migration/output/06-fixed-apis-5.14.4.txt new file mode 100644 index 0000000..0d03325 --- /dev/null +++ b/junit-6-migration/output/06-fixed-apis-5.14.4.txt @@ -0,0 +1,32 @@ +JUnit 5.14.4, compiling FixedApis.java +src/compat/FixedApis.java:1: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.MethodOrderer; + ^ +src/compat/FixedApis.java:2: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.Test; + ^ +src/compat/FixedApis.java:3: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.TestMethodOrder; + ^ +src/compat/FixedApis.java:4: error: package org.junit.platform.commons.support does not exist +import org.junit.platform.commons.support.ReflectionSupport; + ^ +src/compat/FixedApis.java:7: error: cannot find symbol +@TestMethodOrder(MethodOrderer.MethodName.class) + ^ + symbol: class TestMethodOrder +src/compat/FixedApis.java:7: error: package MethodOrderer does not exist +@TestMethodOrder(MethodOrderer.MethodName.class) + ^ +src/compat/FixedApis.java:10: error: cannot find symbol + @Test + ^ + symbol: class Test + location: class FixedApis +src/compat/FixedApis.java:12: error: cannot find symbol + Object loaded = ReflectionSupport.tryToLoadClass("java.lang.String").toOptional().orElseThrow(); + ^ + symbol: variable ReflectionSupport + location: class FixedApis +8 errors +javac exit status: 1 diff --git a/junit-6-migration/output/06-fixed-apis-6.1.3.txt b/junit-6-migration/output/06-fixed-apis-6.1.3.txt new file mode 100644 index 0000000..d07777e --- /dev/null +++ b/junit-6-migration/output/06-fixed-apis-6.1.3.txt @@ -0,0 +1,32 @@ +JUnit 6.1.3, compiling FixedApis.java +src/compat/FixedApis.java:1: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.MethodOrderer; + ^ +src/compat/FixedApis.java:2: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.Test; + ^ +src/compat/FixedApis.java:3: error: package org.junit.jupiter.api does not exist +import org.junit.jupiter.api.TestMethodOrder; + ^ +src/compat/FixedApis.java:4: error: package org.junit.platform.commons.support does not exist +import org.junit.platform.commons.support.ReflectionSupport; + ^ +src/compat/FixedApis.java:7: error: cannot find symbol +@TestMethodOrder(MethodOrderer.MethodName.class) + ^ + symbol: class TestMethodOrder +src/compat/FixedApis.java:7: error: package MethodOrderer does not exist +@TestMethodOrder(MethodOrderer.MethodName.class) + ^ +src/compat/FixedApis.java:10: error: cannot find symbol + @Test + ^ + symbol: class Test + location: class FixedApis +src/compat/FixedApis.java:12: error: cannot find symbol + Object loaded = ReflectionSupport.tryToLoadClass("java.lang.String").toOptional().orElseThrow(); + ^ + symbol: variable ReflectionSupport + location: class FixedApis +8 errors +javac exit status: 1 diff --git a/junit-6-migration/pom.xml b/junit-6-migration/pom.xml new file mode 100644 index 0000000..989658d --- /dev/null +++ b/junit-6-migration/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + com.ankurm + junit-6-migration + 1.0.0 + junit-6-migration + The same tests run on JUnit 5.14.4 and JUnit 6.1.3, plus an API diff of the two releases + + + 17 + UTF-8 + + 6.1.3 + + + + + junit5 + + 5.14.4 + + + + junit6 + + 6.1.3 + + + + + + + + org.junit + junit-bom + ${junit.version} + pom + import + + + + + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.platform + junit-platform-launcher + test + + + org.junit.vintage + junit-vintage-engine + test + + + junit + junit + 4.13.2 + test + + + + + + + maven-surefire-plugin + 3.6.0 + + + ${junit.version} + + + + + + diff --git a/junit-6-migration/scripts/api_diff.py b/junit-6-migration/scripts/api_diff.py new file mode 100755 index 0000000..c2177e6 --- /dev/null +++ b/junit-6-migration/scripts/api_diff.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +"""Compare the public API of JUnit 5.14.4 / Platform 1.14.4 against JUnit 6.1.3 straight from the jars. + +Writes output/01-versions-and-baseline.txt and output/02-removed-api.txt. +Needs a JDK (javap) on PATH or via JAVA_HOME, and access to Maven Central. +""" +import collections +import os +import pathlib +import re +import subprocess +import time +import urllib.error +import urllib.request +import zipfile + +ROOT = pathlib.Path(__file__).resolve().parent.parent +JARS = ROOT / "target" / "jars" +OUT = ROOT / "output" +JAVAP = os.path.join(os.environ["JAVA_HOME"], "bin", "javap") if os.environ.get("JAVA_HOME") else "javap" + +OLD, NEW, PLATFORM_OLD = "5.14.4", "6.1.3", "1.14.4" +ARTIFACTS = [ + ("jupiter", "junit-jupiter-api"), ("jupiter", "junit-jupiter-engine"), ("jupiter", "junit-jupiter-params"), + ("platform", "junit-platform-commons"), ("platform", "junit-platform-engine"), ("platform", "junit-platform-launcher"), + ("platform", "junit-platform-suite-api"), ("platform", "junit-platform-suite-engine"), ("platform", "junit-platform-testkit"), + ("vintage", "junit-vintage-engine"), +] + + +def version_for(group, which): + if which == "new": + return NEW + return PLATFORM_OLD if group == "platform" else OLD + + +def fetch(url, dest): + if dest.exists(): + return + for _ in range(8): + try: + with urllib.request.urlopen(url) as r: + dest.write_bytes(r.read()) + return + except urllib.error.HTTPError as e: + if e.code != 429: + raise + time.sleep(4) + raise RuntimeError("rate limited: " + url) + + +def jar(group, artifact, which): + v = version_for(group, which) + dest = JARS / f"{artifact}-{v}.jar" + fetch(f"https://repo1.maven.org/maven2/org/junit/{group}/{artifact}/{v}/{artifact}-{v}.jar", dest) + return dest + + +def classes(path): + with zipfile.ZipFile(path) as z: + return sorted(n[:-6].replace("/", ".") for n in z.namelist() + if n.endswith(".class") and not n.endswith("module-info.class") and "META-INF" not in n) + + +def major(path): + with zipfile.ZipFile(path) as z: + name = next(n for n in z.namelist() + if n.endswith(".class") and not n.endswith("module-info.class") and "META-INF" not in n) + b = z.read(name) + return int.from_bytes(b[6:8], "big") + + +MEMBER = re.compile(r"^ ((?:public|protected)[^;]*);$") + + +def dump(path): + """One javap call per jar. Returns {class: (is_public, class_deprecated, {member signature: deprecated?})}.""" + names = [c for c in classes(path) if ".internal." not in c] + result = {} + # javap takes many class names at once; split the list to keep the command line short + for i in range(0, len(names), 150): + chunk = names[i:i + 150] + p = subprocess.run([JAVAP, "-v", "-protected", "-cp", str(path)] + chunk, capture_output=True, text=True) + cur_cls = None + for block in re.split(r"(?m)^Classfile ", p.stdout)[1:]: + lines = block.splitlines() + header = lines[0] + cls = re.search(r"!/(.*)\.class", header).group(1).replace("/", ".") + public = False + cls_dep = False + members, cur, in_pool, seen_flags = {}, None, False, False + for line in lines[1:]: + if not seen_flags and line.startswith(" flags:"): + public = "ACC_PUBLIC" in line + seen_flags = True + if line.startswith("Constant pool:"): + in_pool = True + continue + if in_pool: + if line.startswith("{"): + in_pool = False + continue + m = MEMBER.match(line) + if m: + cur = " ".join(m.group(1).split()) + members[cur] = False + continue + if line.strip() == "Deprecated: true": + if cur is None: + cls_dep = True + else: + members[cur] = True + if line.startswith("}"): + cur = None + if re.search(r"^Deprecated: true", block, re.M): + cls_dep = True + result[cls] = (public, cls_dep, members) + return result + + +def main(): + JARS.mkdir(parents=True, exist_ok=True) + OUT.mkdir(parents=True, exist_ok=True) + versions = [f"{'artifact':<34} {'5.x jar':<28} {'6.x jar':<28}"] + removed_classes = collections.defaultdict(list) + removed_members = collections.defaultdict(list) + added = collections.Counter() + for group, art in ARTIFACTS: + old, new = jar(group, art, "old"), jar(group, art, "new") + mo, mn = major(old), major(new) + versions.append(f"{art:<34} {version_for(group, 'old')} (Java {mo - 44}){'':<9} {NEW} (Java {mn - 44})") + do, dn = dump(old), dump(new) + co, cn = set(classes(old)), set(classes(new)) + for c in sorted(co - cn): + if c in do and do[c][0]: + removed_classes[art].append((c, do[c][1])) + added[art] = len(cn - co) + for c in sorted(do): + if c in dn and do[c][0]: + for sig, dep in do[c][2].items(): + if sig not in dn[c][2]: + removed_members[art].append((c, sig, dep)) + (OUT / "01-versions-and-baseline.txt").write_text("\n".join(versions) + "\n") + lines = [] + for _, art in ARTIFACTS: + lines.append(f"== {art}: public classes removed: {len(removed_classes[art])}, " + f"members removed from classes that remain: {len(removed_members[art])}, " + f"new classes: {added[art]}") + for c, dep in removed_classes[art]: + lines.append(f" class {c} [{'deprecated in 5.x' if dep else 'NOT deprecated in 5.x'}]") + for c, sig, dep in removed_members[art]: + lines.append(f" member {c}: {sig} [{'deprecated in 5.x' if dep else 'NOT deprecated in 5.x'}]") + (OUT / "02-removed-api.txt").write_text("\n".join(lines) + "\n") + print("\n".join(versions)) + print("\n".join(l for l in lines if l.startswith("=="))) + + +if __name__ == "__main__": + main() diff --git a/junit-6-migration/scripts/compile-old-apis.sh b/junit-6-migration/scripts/compile-old-apis.sh new file mode 100755 index 0000000..2f90f40 --- /dev/null +++ b/junit-6-migration/scripts/compile-old-apis.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Compiles src/compat/OldApis.java against the JUnit 5.14.4 jars and then the 6.1.3 jars and records the compiler's answer. +# Run scripts/api_diff.py first: it downloads the jars into target/jars. +set -uo pipefail +cd "$(dirname "$0")/.." +unset JAVA_TOOL_OPTIONS +mkdir -p output target/compat +J=target/jars +[ -f "$J/apiguardian-api-1.1.2.jar" ] || curl -sSf --retry 5 -o "$J/apiguardian-api-1.1.2.jar" \ + https://repo1.maven.org/maven2/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar +compile() { # $1 = label, $2 = jupiter version, $3 = platform version + for src in OldApis:05-old-apis FixedApis:06-fixed-apis; do + { + echo "JUnit $2, compiling ${src%%:*}.java" + javac -Xlint:deprecation --release 17 -d "target/compat/$1" \ + -cp "$J/junit-jupiter-api-$2.jar:$J/junit-platform-commons-$3.jar:$J/apiguardian-api-1.1.2.jar" "src/compat/${src%%:*}.java" 2>&1 \ + | sed -e '/^Picked up/d' + echo "javac exit status: ${PIPESTATUS[0]}" + } > "output/${src##*:}-$2.txt" + done +} +compile junit5 5.14.4 1.14.4 +compile junit6 6.1.3 6.1.3 diff --git a/junit-6-migration/scripts/run-all.sh b/junit-6-migration/scripts/run-all.sh new file mode 100755 index 0000000..7c3f228 --- /dev/null +++ b/junit-6-migration/scripts/run-all.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# Regenerates every file in output/. Needs JDK 17+ (built with 25), Maven 3.9 and access to Maven Central. +set -euo pipefail +cd "$(dirname "$0")/.." +unset JAVA_TOOL_OPTIONS + +python3 scripts/api_diff.py >/dev/null # 01, 02: jar-to-jar API diff (also downloads the jars) +mvn -B -q clean test -Pjunit5 # 03, 04 on JUnit 5.14.4 +mvn -B -q clean test -Pjunit6 # 03, 04 on JUnit 6.1.3 +./scripts/compile-old-apis.sh # 05, 06 +ls -1 output diff --git a/junit-6-migration/src/compat/FixedApis.java b/junit-6-migration/src/compat/FixedApis.java new file mode 100644 index 0000000..79ab40d --- /dev/null +++ b/junit-6-migration/src/compat/FixedApis.java @@ -0,0 +1,15 @@ +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.platform.commons.support.ReflectionSupport; + +/** The replacements for OldApis. This compiles on 5.14.4 and on 6.1.3, so make these changes before you upgrade. */ +@TestMethodOrder(MethodOrderer.MethodName.class) +class FixedApis { + + @Test + void usesTheReplacements() { + Object loaded = ReflectionSupport.tryToLoadClass("java.lang.String").toOptional().orElseThrow(); + System.out.println(loaded); + } +} diff --git a/junit-6-migration/src/compat/OldApis.java b/junit-6-migration/src/compat/OldApis.java new file mode 100644 index 0000000..a947eea --- /dev/null +++ b/junit-6-migration/src/compat/OldApis.java @@ -0,0 +1,17 @@ +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.io.TempDir; +import org.junit.platform.commons.support.ReflectionSupport; + +/** Compiled by scripts/compile-old-apis.sh against each JUnit version. Not part of the Maven build. */ +@TestMethodOrder(MethodOrderer.Alphanumeric.class) +class OldApis { + + @Test + void usesRemovedApis() { + Object loaded = ReflectionSupport.loadClass("java.lang.String"); + String property = TempDir.SCOPE_PROPERTY_NAME; + System.out.println(loaded + " " + property); + } +} diff --git a/junit-6-migration/src/test/java/com/ankurm/junitmigration/BehaviourTest.java b/junit-6-migration/src/test/java/com/ankurm/junitmigration/BehaviourTest.java new file mode 100644 index 0000000..dd2fc94 --- /dev/null +++ b/junit-6-migration/src/test/java/com/ankurm/junitmigration/BehaviourTest.java @@ -0,0 +1,86 @@ +package com.ankurm.junitmigration; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.launcher.TestExecutionListener; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; +import org.junit.platform.launcher.core.LauncherFactory; + +/** + * Runs the same probe classes on whichever JUnit is on the class path and writes what happened to + * output/NN-name-<version>.txt. The two versions are meant to give different answers in places, so this + * test records them instead of asserting them. It does assert that the probes ran at all. + */ +class BehaviourTest { + + private static final String VERSION = System.getProperty("junit.version", "unknown"); + + @Test + void csvBehaviour() throws IOException { + List lines = run(CsvProbe.class); + write("03-csv-behaviour", lines); + assertTrue(lines.size() > 10, "probe produced results"); + } + + @Test + void vintageStillRunsJUnit4() throws IOException { + List lines = run(LegacyJUnit4Test.class); + write("04-vintage-junit4", lines); + assertTrue(lines.stream().anyMatch(l -> l.contains("stillRuns") && l.contains("SUCCESSFUL")), "junit 4 test ran"); + } + + private static List run(Class probe) { + List lines = new ArrayList<>(); + var request = LauncherDiscoveryRequestBuilder.request().selectors(selectClass(probe)).build(); + var launcher = LauncherFactory.create(); + launcher.execute(request, new TestExecutionListener() { + @Override + public void executionSkipped(TestIdentifier id, String reason) { + lines.add(String.format("%-11s %s -> %s", "SKIPPED", id.getDisplayName(), reason)); + } + + @Override + public void executionFinished(TestIdentifier id, TestExecutionResult result) { + // a parameterized method is a container: report it too when it fails as a whole + if (!id.isTest() && result.getStatus() == TestExecutionResult.Status.SUCCESSFUL) { + return; + } + if (!id.isTest() && id.getParentId().isEmpty()) { + return; + } + String outcome = result.getStatus().name(); + String message = result.getThrowable().map(t -> " -> " + t.getClass().getSimpleName() + ": " + + firstLine(t.getMessage())).orElse(""); + lines.add(String.format("%-11s %s%s%s", outcome, id.isTest() ? "" : "[method] ", id.getDisplayName(), message)); + } + }); + return lines; + } + + private static String firstLine(String s) { + if (s == null) { + return ""; + } + String one = s.lines().findFirst().orElse(""); + return one.length() > 110 ? one.substring(0, 110) + "..." : one; + } + + private static void write(String name, List lines) throws IOException { + Path dir = Path.of("output"); + Files.createDirectories(dir); + List out = new ArrayList<>(); + out.add("JUnit " + VERSION); + out.addAll(lines); + Files.write(dir.resolve(name + "-" + VERSION + ".txt"), out); + } +} diff --git a/junit-6-migration/src/test/java/com/ankurm/junitmigration/CsvProbe.java b/junit-6-migration/src/test/java/com/ankurm/junitmigration/CsvProbe.java new file mode 100644 index 0000000..567f80a --- /dev/null +++ b/junit-6-migration/src/test/java/com/ankurm/junitmigration/CsvProbe.java @@ -0,0 +1,56 @@ +package com.ankurm.junitmigration; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvFileSource; +import org.junit.jupiter.params.provider.CsvSource; + +/** + * Not run by Surefire (the name does not end in Test). {@link BehaviourTest} launches it through the + * JUnit Platform Launcher and records what each invocation was called and whether it passed, on whichever + * JUnit version is on the class path. + */ +class CsvProbe { + + @ParameterizedTest + @CsvSource({ + "apple, 1", + "'a,b', 2", + " padded , 3", + "'', 4", + ", 5", + "NIL, 6", + "'it''s', 7", + "\"dq\", 8" + }) + void basicRows(String name, int n) { + } + + @ParameterizedTest + @CsvSource(value = {"x;1", "y;2"}, delimiter = ';', useHeadersInDisplayName = false) + void customDelimiter(String name, int n) { + } + + @ParameterizedTest + @CsvSource(textBlock = """ + name, qty + widget, 4 + 'multi word', 5 + """, useHeadersInDisplayName = true) + void textBlockWithHeader(String name, int qty) { + } + + @ParameterizedTest + @CsvSource(value = {"a,b,c"}) + void tooManyColumnsForParameters(String first) { + } + + @ParameterizedTest + @CsvSource(value = {"1234567890,1"}, maxCharsPerColumn = 5) + void columnLongerThanLimit(String value, int n) { + } + + @ParameterizedTest + @CsvFileSource(resources = "/probe.csv", numLinesToSkip = 1) + void fileRows(String name, int n) { + } +} diff --git a/junit-6-migration/src/test/java/com/ankurm/junitmigration/LegacyJUnit4Test.java b/junit-6-migration/src/test/java/com/ankurm/junitmigration/LegacyJUnit4Test.java new file mode 100644 index 0000000..760c511 --- /dev/null +++ b/junit-6-migration/src/test/java/com/ankurm/junitmigration/LegacyJUnit4Test.java @@ -0,0 +1,14 @@ +package com.ankurm.junitmigration; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +/** A JUnit 4 test. It is discovered by the Vintage engine, not by Jupiter. */ +public class LegacyJUnit4Test { + + @Test + public void stillRuns() { + assertEquals(4, 2 + 2); + } +} diff --git a/junit-6-migration/src/test/resources/probe.csv b/junit-6-migration/src/test/resources/probe.csv new file mode 100644 index 0000000..2446f2e --- /dev/null +++ b/junit-6-migration/src/test/resources/probe.csv @@ -0,0 +1,5 @@ +name,n +one,1 +"two, with comma",2 +"line +break",3